Contract 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e5

Contract Overview

Balance:
0 BNB
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x5597930378f76e4532644c6ae6e404f1d09ee102ad7aad586048b49602296a150x6080604083976222021-04-29 7:57:37144 days 13 hrs ago0x20000b9b01e93a39db9d286e9264eff7f2af16e9 IN  Contract Creation0 BNB0.04620866
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x0cb56f9298a9a366d7b5341fab7eae265adeaf29dac66fd45a3c3c2510d393eb92317772021-05-28 8:09:02115 days 13 hrs ago 0xe121eadca088e433751543477a088592f16e6798 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0x894efae7102784ca378bb24fbe2581744df0f9baf8a1995bff8adb5464827b1192317772021-05-28 8:09:02115 days 13 hrs ago 0x4e1c4114247ef76177bdc3e1d43f361e7cc42bb3 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0xca18c999db51acfc8b32a7abac2ae58becb27936cd3162cabff875cc9944a02792317762021-05-28 8:08:59115 days 13 hrs ago 0xbdcac02c00f7412959724d19490ecbe22e515728 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0xca18c999db51acfc8b32a7abac2ae58becb27936cd3162cabff875cc9944a02792317762021-05-28 8:08:59115 days 13 hrs ago 0xbdcac02c00f7412959724d19490ecbe22e515728 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0xca18c999db51acfc8b32a7abac2ae58becb27936cd3162cabff875cc9944a02792317762021-05-28 8:08:59115 days 13 hrs ago 0xbdcac02c00f7412959724d19490ecbe22e515728 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0xca18c999db51acfc8b32a7abac2ae58becb27936cd3162cabff875cc9944a02792317762021-05-28 8:08:59115 days 13 hrs ago 0xbdcac02c00f7412959724d19490ecbe22e515728 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0xca18c999db51acfc8b32a7abac2ae58becb27936cd3162cabff875cc9944a02792317762021-05-28 8:08:59115 days 13 hrs ago 0xbdcac02c00f7412959724d19490ecbe22e515728 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0xca18c999db51acfc8b32a7abac2ae58becb27936cd3162cabff875cc9944a02792317762021-05-28 8:08:59115 days 13 hrs ago 0xbdcac02c00f7412959724d19490ecbe22e515728 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
0xca18c999db51acfc8b32a7abac2ae58becb27936cd3162cabff875cc9944a02792317762021-05-28 8:08:59115 days 13 hrs ago 0xbdcac02c00f7412959724d19490ecbe22e515728 0xe4e2858caa2ef7aeab0b6324b9fabe916a5093e50 BNB
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Exchange

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at BscScan.com on 2021-04-29
*/

// File: @openzeppelin\contracts-upgradeable\token\ERC20\IERC20Upgradeable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @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);
}


// File: node_modules\@openzeppelin\contracts-upgradeable\math\SafeMathUpgradeable.sol


pragma solidity >=0.6.0 <0.8.0;

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

// File: node_modules\@openzeppelin\contracts-upgradeable\utils\AddressUpgradeable.sol


pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @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);
    }

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

// File: @openzeppelin\contracts-upgradeable\token\ERC20\SafeERC20Upgradeable.sol


pragma solidity >=0.6.0 <0.8.0;




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

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

    function safeTransferFrom(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

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

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20Upgradeable 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");
        }
    }
}


// File: node_modules\@openzeppelin\contracts-upgradeable\proxy\Initializable.sol


// solhint-disable-next-line compiler-version
pragma solidity >=0.4.24 <0.8.0;


/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 * 
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
 * 
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 */
abstract contract Initializable {

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

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

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

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

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

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

// File: node_modules\@openzeppelin\contracts-upgradeable\GSN\ContextUpgradeable.sol

pragma solidity >=0.6.0 <0.8.0;


/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal initializer {
        __Context_init_unchained();
    }

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

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

// File: @openzeppelin\contracts-upgradeable\access\OwnableUpgradeable.sol


pragma solidity >=0.6.0 <0.8.0;


/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal initializer {
        __Context_init_unchained();
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal initializer {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
    uint256[49] private __gap;
}

// File: contracts\interface\IPriceFeed.sol

pragma solidity ^0.6.12;

interface IPriceFeed {
    // get latest price
    function getPrice(bytes32 _priceFeedKey) external view returns (uint256);

    // get twap price depending on _period
    function getTwapPrice(bytes32 _priceFeedKey, uint256 _interval) external view returns (uint256);
}

// File: contracts\utils\DecimalMath.sol

pragma solidity ^0.6.12;


/// @dev Implements simple fixed point math add, sub, mul and div operations.
/// @author Alberto Cuesta Cañada
library DecimalMath {
    using SafeMathUpgradeable for uint256;

    /// @dev Returns 1 in the fixed point representation, with `decimals` decimals.
    function unit(uint8 decimals) internal pure returns (uint256) {
        return 10**uint256(decimals);
    }

    /// @dev Adds x and y, assuming they are both fixed point with 18 decimals.
    function addd(uint256 x, uint256 y) internal pure returns (uint256) {
        return x.add(y);
    }

    /// @dev Subtracts y from x, assuming they are both fixed point with 18 decimals.
    function subd(uint256 x, uint256 y) internal pure returns (uint256) {
        return x.sub(y);
    }

    /// @dev Multiplies x and y, assuming they are both fixed point with 18 digits.
    function muld(uint256 x, uint256 y) internal pure returns (uint256) {
        return muld(x, y, 18);
    }

    /// @dev Multiplies x and y, assuming they are both fixed point with `decimals` digits.
    function muld(
        uint256 x,
        uint256 y,
        uint8 decimals
    ) internal pure returns (uint256) {
        return x.mul(y).div(unit(decimals));
    }

    /// @dev Divides x between y, assuming they are both fixed point with 18 digits.
    function divd(uint256 x, uint256 y) internal pure returns (uint256) {
        return divd(x, y, 18);
    }

    /// @dev Divides x between y, assuming they are both fixed point with `decimals` digits.
    function divd(
        uint256 x,
        uint256 y,
        uint8 decimals
    ) internal pure returns (uint256) {
        return x.mul(unit(decimals)).div(y);
    }
}

// File: contracts\utils\Decimal.sol

pragma solidity ^0.6.12;



library Decimal {
    using DecimalMath for uint256;
    using SafeMathUpgradeable for uint256;

    struct decimal {
        uint256 d;
    }

    function zero() internal pure returns (decimal memory) {
        return decimal(0);
    }

    function one() internal pure returns (decimal memory) {
        return decimal(DecimalMath.unit(18));
    }

    function toUint(decimal memory x) internal pure returns (uint256) {
        return x.d;
    }

    function modD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        return decimal(x.d.mul(DecimalMath.unit(18)) % y.d);
    }

    function cmp(decimal memory x, decimal memory y) internal pure returns (int8) {
        if (x.d > y.d) {
            return 1;
        } else if (x.d < y.d) {
            return -1;
        }
        return 0;
    }

    /// @dev add two decimals
    function addD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.add(y.d);
        return t;
    }

    /// @dev subtract two decimals
    function subD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.sub(y.d);
        return t;
    }

    /// @dev multiple two decimals
    function mulD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.muld(y.d);
        return t;
    }

    /// @dev multiple a decimal by a uint256
    function mulScalar(decimal memory x, uint256 y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.mul(y);
        return t;
    }

    /// @dev divide two decimals
    function divD(decimal memory x, decimal memory y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.divd(y.d);
        return t;
    }

    /// @dev divide a decimal by a uint256
    function divScalar(decimal memory x, uint256 y) internal pure returns (decimal memory) {
        decimal memory t;
        t.d = x.d.div(y);
        return t;
    }
}

// File: @openzeppelin\contracts-upgradeable\math\SignedSafeMathUpgradeable.sol


pragma solidity >=0.6.0 <0.8.0;

/**
 * @title SignedSafeMath
 * @dev Signed math operations with safety checks that revert on error.
 */
library SignedSafeMathUpgradeable {
    int256 constant private _INT256_MIN = -2**255;

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

        require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");

        int256 c = a * b;
        require(c / a == b, "SignedSafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, "SignedSafeMath: division by zero");
        require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");

        int256 c = a / b;

        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");

        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");

        return c;
    }
}

// File: contracts\utils\SignedDecimalMath.sol

pragma solidity ^0.6.12;


/// @dev Implements simple signed fixed point math add, sub, mul and div operations.
library SignedDecimalMath {
    using SignedSafeMathUpgradeable for int256;

    /// @dev Returns 1 in the fixed point representation, with `decimals` decimals.
    function unit(uint8 decimals) internal pure returns (int256) {
        return int256(10**uint256(decimals));
    }

    /// @dev Adds x and y, assuming they are both fixed point with 18 decimals.
    function addd(int256 x, int256 y) internal pure returns (int256) {
        return x.add(y);
    }

    /// @dev Subtracts y from x, assuming they are both fixed point with 18 decimals.
    function subd(int256 x, int256 y) internal pure returns (int256) {
        return x.sub(y);
    }

    /// @dev Multiplies x and y, assuming they are both fixed point with 18 digits.
    function muld(int256 x, int256 y) internal pure returns (int256) {
        return muld(x, y, 18);
    }

    /// @dev Multiplies x and y, assuming they are both fixed point with `decimals` digits.
    function muld(
        int256 x,
        int256 y,
        uint8 decimals
    ) internal pure returns (int256) {
        return x.mul(y).div(unit(decimals));
    }

    /// @dev Divides x between y, assuming they are both fixed point with 18 digits.
    function divd(int256 x, int256 y) internal pure returns (int256) {
        return divd(x, y, 18);
    }

    /// @dev Divides x between y, assuming they are both fixed point with `decimals` digits.
    function divd(
        int256 x,
        int256 y,
        uint8 decimals
    ) internal pure returns (int256) {
        return x.mul(unit(decimals)).div(y);
    }
}

// File: contracts\utils\SignedDecimal.sol

pragma solidity ^0.6.12;




library SignedDecimal {
    using SignedDecimalMath for int256;
    using SignedSafeMathUpgradeable for int256;

    struct signedDecimal {
        int256 d;
    }

    function zero() internal pure returns (signedDecimal memory) {
        return signedDecimal(0);
    }

    function toInt(signedDecimal memory x) internal pure returns (int256) {
        return x.d;
    }

    function isNegative(signedDecimal memory x) internal pure returns (bool) {
        if (x.d < 0) {
            return true;
        }
        return false;
    }

    function abs(signedDecimal memory x) internal pure returns (Decimal.decimal memory) {
        Decimal.decimal memory t;
        if (x.d < 0) {
            t.d = uint256(0 - x.d);
        } else {
            t.d = uint256(x.d);
        }
        return t;
    }

    /// @dev add two decimals
    function addD(signedDecimal memory x, signedDecimal memory y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.add(y.d);
        return t;
    }

    /// @dev subtract two decimals
    function subD(signedDecimal memory x, signedDecimal memory y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.sub(y.d);
        return t;
    }

    /// @dev multiple two decimals
    function mulD(signedDecimal memory x, signedDecimal memory y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.muld(y.d);
        return t;
    }

    /// @dev multiple a signedDecimal by a int256
    function mulScalar(signedDecimal memory x, int256 y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.mul(y);
        return t;
    }

    /// @dev divide two decimals
    function divD(signedDecimal memory x, signedDecimal memory y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.divd(y.d);
        return t;
    }

    /// @dev divide a signedDecimal by a int256
    function divScalar(signedDecimal memory x, int256 y) internal pure returns (signedDecimal memory) {
        signedDecimal memory t;
        t.d = x.d.div(y);
        return t;
    }
}

// File: contracts\types\ISakePerpVaultTypes.sol

pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

interface ISakePerpVaultTypes {
    /**
     * @notice pool types
     * @param HIGH high risk pool
     * @param LOW low risk pool
     */
    enum Risk {HIGH, LOW}
}

// File: contracts\types\IExchangeTypes.sol

pragma solidity ^0.6.12;




interface IExchangeTypes {
    /**
     * @notice asset direction, used in getInputPrice, getOutputPrice, swapInput and swapOutput
     * @param ADD_TO_AMM add asset to Amm
     * @param REMOVE_FROM_AMM remove asset from Amm
     */
    enum Dir {ADD_TO_AMM, REMOVE_FROM_AMM}

    struct LiquidityChangedSnapshot {
        SignedDecimal.signedDecimal cumulativeNotional;
        // the base/quote reserve of amm right before liquidity changed
        Decimal.decimal quoteAssetReserve;
        Decimal.decimal baseAssetReserve;
        // total position size owned by amm after last snapshot taken
        // `totalPositionSize` = currentBaseAssetReserve - lastLiquidityChangedHistoryItem.baseAssetReserve + prevTotalPositionSize
        SignedDecimal.signedDecimal totalPositionSize;
    }
}

// File: @openzeppelin\contracts-upgradeable\token\ERC20\ERC20Upgradeable.sol


pragma solidity >=0.6.0 <0.8.0;


/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable {
    using SafeMathUpgradeable for uint256;

    mapping (address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    function __ERC20_init(string memory name_, string memory symbol_) internal initializer {
        __Context_init_unchained();
        __ERC20_init_unchained(name_, symbol_);
    }

    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer {
        _name = name_;
        _symbol = symbol_;
        _decimals = 18;
    }

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

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

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

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

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

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

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

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

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

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

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

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

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

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

        _beforeTokenTransfer(address(0), account, amount);

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

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

        _beforeTokenTransfer(account, address(0), amount);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

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

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

    /**
     * @dev Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
    uint256[44] private __gap;
}

// File: contracts\MMLPToken.sol

pragma solidity ^0.6.12;



contract MMLPToken is ERC20Upgradeable, OwnableUpgradeable {
    constructor(string memory _name, string memory _symbol) public {
        __ERC20_init(_name, _symbol);
        __Ownable_init();
    }

    function mint(address _account, uint256 _amount) external onlyOwner {
        _mint(_account, _amount);
    }

    function burn(address _account, uint256 _amount) external onlyOwner {
        _burn(_account, _amount);
    }
}

// File: contracts\interface\IExchangeState.sol


pragma solidity ^0.6.12;



interface IExchangeState {
    function getMaxHoldingBaseAsset() external view returns (Decimal.decimal memory);

    function getOpenInterestNotionalCap() external view returns (Decimal.decimal memory);

    function initMarginRatio() external view returns (Decimal.decimal memory);

    function maintenanceMarginRatio() external view returns (Decimal.decimal memory);

    function liquidationFeeRatio() external view returns (Decimal.decimal memory);

    function maxLiquidationFee() external view returns (Decimal.decimal memory);

    function spreadRatio() external view returns (Decimal.decimal memory);

    function maxOracleSpreadRatio() external view returns (Decimal.decimal memory);

    function getInputPriceWithReserves(
        IExchangeTypes.Dir _dir,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) external pure returns (Decimal.decimal memory);

    function getOutputPriceWithReserves(
        IExchangeTypes.Dir _dir,
        Decimal.decimal memory _baseAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) external pure returns (Decimal.decimal memory);

    function calcFee(Decimal.decimal calldata _quoteAssetAmount) external view returns (Decimal.decimal memory);

    function mint(
        ISakePerpVaultTypes.Risk _level,
        address account,
        uint256 amount
    ) external;

    function burn(
        ISakePerpVaultTypes.Risk _level,
        address account,
        uint256 amount
    ) external;

    function getLPToken(ISakePerpVaultTypes.Risk _level) external view returns (MMLPToken);
}

// File: contracts\interface\IExchange.sol

pragma solidity ^0.6.12;


interface IExchange is IExchangeTypes {
    function swapInput(
        Dir _dir,
        Decimal.decimal calldata _quoteAssetAmount,
        Decimal.decimal calldata _baseAssetAmountLimit
    ) external returns (Decimal.decimal memory);

    function swapOutput(
        Dir _dir,
        Decimal.decimal calldata _baseAssetAmount,
        Decimal.decimal calldata _quoteAssetAmountLimit,
        bool _skipFluctuationCheck
    ) external returns (Decimal.decimal memory);

    function migrateLiquidity(Decimal.decimal calldata _liquidityMultiplier, Decimal.decimal calldata _priceLimitRatio)
        external;

    function shutdown() external;

    function settleFunding() external returns (SignedDecimal.signedDecimal memory);

    function calcFee(Decimal.decimal calldata _quoteAssetAmount) external view returns (Decimal.decimal memory);

    function calcBaseAssetAfterLiquidityMigration(
        SignedDecimal.signedDecimal memory _baseAssetAmount,
        Decimal.decimal memory _fromQuoteReserve,
        Decimal.decimal memory _fromBaseReserve
    ) external view returns (SignedDecimal.signedDecimal memory);

    function getInputTwap(Dir _dir, Decimal.decimal calldata _quoteAssetAmount)
        external
        view
        returns (Decimal.decimal memory);

    function getOutputTwap(Dir _dir, Decimal.decimal calldata _baseAssetAmount)
        external
        view
        returns (Decimal.decimal memory);

    function getInputPrice(Dir _dir, Decimal.decimal calldata _quoteAssetAmount)
        external
        view
        returns (Decimal.decimal memory);

    function getOutputPrice(Dir _dir, Decimal.decimal calldata _baseAssetAmount)
        external
        view
        returns (Decimal.decimal memory);

    function getInputPriceWithReserves(
        Dir _dir,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) external view returns (Decimal.decimal memory);

    function getOutputPriceWithReserves(
        Dir _dir,
        Decimal.decimal memory _baseAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) external view returns (Decimal.decimal memory);

    function getSpotPrice() external view returns (Decimal.decimal memory);

    function getLiquidityHistoryLength() external view returns (uint256);

    // overridden by state variable
    function quoteAsset() external view returns (IERC20Upgradeable);

    function open() external view returns (bool);

    // can not be overridden by state variable due to type `Deciaml.decimal`
    function getSettlementPrice() external view returns (Decimal.decimal memory);

    function getCumulativeNotional() external view returns (SignedDecimal.signedDecimal memory);

    function getMaxHoldingBaseAsset() external view returns (Decimal.decimal memory);

    function getOpenInterestNotionalCap() external view returns (Decimal.decimal memory);

    function getLiquidityChangedSnapshots(uint256 i) external view returns (LiquidityChangedSnapshot memory);

    function mint(
        ISakePerpVaultTypes.Risk _level,
        address account,
        uint256 amount
    ) external;

    function burn(
        ISakePerpVaultTypes.Risk _level,
        address account,
        uint256 amount
    ) external;

    function getMMUnrealizedPNL(Decimal.decimal memory _baseAssetReserve, Decimal.decimal memory _quoteAssetReserve)
        external
        view
        returns (SignedDecimal.signedDecimal memory);

    function moveAMMPriceToOracle(uint256 _oraclePrice, bytes32 _priceFeedKey) external;

    function setPriceFeed(address _priceFeed) external;

    function getReserve() external view returns (Decimal.decimal memory, Decimal.decimal memory);

    function initMarginRatio() external view returns (Decimal.decimal memory);

    function maintenanceMarginRatio() external view returns (Decimal.decimal memory);

    function liquidationFeeRatio() external view returns (Decimal.decimal memory);

    function maxLiquidationFee() external view returns (Decimal.decimal memory);

    function spreadRatio() external view returns (Decimal.decimal memory);

    function priceFeedKey() external view returns (bytes32);

    function tradeLimitRatio() external view returns (uint256);

    function priceAdjustRatio() external view returns (uint256);

    function fluctuationLimitRatio() external view returns (uint256);

    function fundingPeriod() external view returns (uint256);

    function adjustTotalPosition(
        SignedDecimal.signedDecimal memory adjustedPosition,
        SignedDecimal.signedDecimal memory oldAdjustedPosition
    ) external;

    function getTotalPositionSize() external view returns (SignedDecimal.signedDecimal memory);

    function exchangeState() external view returns (IExchangeState);

    function getUnderlyingPrice() external view returns (Decimal.decimal memory);

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

// File: contracts\types\ISakePerpTypes.sol

pragma solidity ^0.6.12;


interface ISakePerpTypes {
    //
    // Struct and Enum
    //
    enum Side {BUY, SELL}
    enum PnlCalcOption { SPOT_PRICE, TWAP, ORACLE }

    /// @notice This struct records personal position information
    /// @param size denominated in amm.baseAsset
    /// @param margin isolated margin
    /// @param openNotional the quoteAsset value of position when opening position. the cost of the position
    /// @param lastUpdatedCumulativePremiumFraction for calculating funding payment, record at the moment every time when trader open/reduce/close position
    /// @param lastUpdatedCumulativeOvernightFeeRate for calculating holding fee, record at the moment every time when trader open/reduce/close position
    /// @param liquidityHistoryIndex
    /// @param blockNumber the block number of the last position
    struct Position {
        SignedDecimal.signedDecimal size;
        Decimal.decimal margin;
        Decimal.decimal openNotional;
        SignedDecimal.signedDecimal lastUpdatedCumulativePremiumFraction;
        Decimal.decimal lastUpdatedCumulativeOvernightFeeRate;
        uint256 liquidityHistoryIndex;
        uint256 blockNumber;
    }
}

// File: contracts\interface\ISakePerp.sol

pragma solidity ^0.6.12;


interface ISakePerp is ISakePerpTypes {
    function getMMLiquidity(address _exchange) external view returns (SignedDecimal.signedDecimal memory);

    function getLatestCumulativePremiumFraction(IExchange _exchange)
        external
        view
        returns (SignedDecimal.signedDecimal memory);

    function getLatestCumulativeOvernightFeeRate(IExchange _exchange) external view returns (Decimal.decimal memory);

    function getPositionNotionalAndUnrealizedPnl(
        IExchange _exchange,
        address _trader,
        PnlCalcOption _pnlCalcOption
    ) external view returns (Decimal.decimal memory positionNotional, SignedDecimal.signedDecimal memory unrealizedPnl);

    function getPosition(IExchange _exchange, address _trader) external view returns (Position memory);

    function getUnadjustedPosition(IExchange _exchange, address _trader)
        external
        view
        returns (Position memory position);

    function getMarginRatio(IExchange _exchange, address _trader)
        external
        view
        returns (SignedDecimal.signedDecimal memory);
}

// File: contracts\interface\ISakePerpVault.sol

pragma solidity ^0.6.12;


interface ISakePerpVault is ISakePerpVaultTypes {
    function withdraw(
        IExchange _exchange,
        address _receiver,
        Decimal.decimal memory _amount
    ) external;

    function realizeBadDebt(IExchange _exchange, Decimal.decimal memory _badDebt) external;

    function modifyLiquidity() external;

    function getMMLiquidity(address _exchange, Risk _risk) external view returns (SignedDecimal.signedDecimal memory);

    function getAllMMLiquidity(address _exchange)
        external
        view
        returns (SignedDecimal.signedDecimal memory, SignedDecimal.signedDecimal memory);

    function getTotalMMLiquidity(address _exchange) external view returns (SignedDecimal.signedDecimal memory);

    function getTotalMMAvailableLiquidity(address _exchange) external view returns (SignedDecimal.signedDecimal memory);

    function getTotalLpUnrealizedPNL(IExchange _exchange) external view returns (SignedDecimal.signedDecimal memory);

    function addCachedLiquidity(address _exchange, Decimal.decimal memory _DeltalpLiquidity) external;

    function requireMMNotBankrupt(address _exchange) external;

    function getMMCachedLiquidity(address _exchange, Risk _risk) external view returns (Decimal.decimal memory);

    function getTotalMMCachedLiquidity(address _exchange) external view returns (Decimal.decimal memory);

    function setHighRiskLiquidityWeight(address _exchange, uint256 _weight) external;

    function setMaxLoss(
        address _exchange,
        Risk _risk,
        uint256 _max
    ) external;
}

// File: contracts\utils\MixedDecimal.sol

pragma solidity ^0.6.12;

/// @dev To handle a signedDecimal add/sub/mul/div a decimal and provide convert decimal to signedDecimal helper
library MixedDecimal {
    using SignedDecimal for SignedDecimal.signedDecimal;
    using SignedSafeMathUpgradeable for int256;

    uint256 private constant _INT256_MAX = 2**255 - 1;
    string private constant ERROR_NON_CONVERTIBLE = "MixedDecimal: uint value is bigger than _INT256_MAX";

    modifier convertible(Decimal.decimal memory x) {
        require(_INT256_MAX >= x.d, ERROR_NON_CONVERTIBLE);
        _;
    }

    function fromDecimal(Decimal.decimal memory x)
        internal
        pure
        convertible(x)
        returns (SignedDecimal.signedDecimal memory)
    {
        return SignedDecimal.signedDecimal(int256(x.d));
    }

    function toUint(SignedDecimal.signedDecimal memory x) internal pure returns (uint256) {
        return x.abs().d;
    }

    /// @dev add SignedDecimal.signedDecimal and Decimal.decimal, using SignedSafeMath directly
    function addD(SignedDecimal.signedDecimal memory x, Decimal.decimal memory y)
        internal
        pure
        convertible(y)
        returns (SignedDecimal.signedDecimal memory)
    {
        SignedDecimal.signedDecimal memory t;
        t.d = x.d.add(int256(y.d));
        return t;
    }

    /// @dev subtract SignedDecimal.signedDecimal by Decimal.decimal, using SignedSafeMath directly
    function subD(SignedDecimal.signedDecimal memory x, Decimal.decimal memory y)
        internal
        pure
        convertible(y)
        returns (SignedDecimal.signedDecimal memory)
    {
        SignedDecimal.signedDecimal memory t;
        t.d = x.d.sub(int256(y.d));
        return t;
    }

    /// @dev multiple a SignedDecimal.signedDecimal by Decimal.decimal
    function mulD(SignedDecimal.signedDecimal memory x, Decimal.decimal memory y)
        internal
        pure
        convertible(y)
        returns (SignedDecimal.signedDecimal memory)
    {
        SignedDecimal.signedDecimal memory t;
        t = x.mulD(fromDecimal(y));
        return t;
    }

    /// @dev multiple a SignedDecimal.signedDecimal by a uint256
    function mulScalar(SignedDecimal.signedDecimal memory x, uint256 y)
        internal
        pure
        returns (SignedDecimal.signedDecimal memory)
    {
        require(_INT256_MAX >= y, ERROR_NON_CONVERTIBLE);
        SignedDecimal.signedDecimal memory t;
        t = x.mulScalar(int256(y));
        return t;
    }

    /// @dev divide a SignedDecimal.signedDecimal by a Decimal.decimal
    function divD(SignedDecimal.signedDecimal memory x, Decimal.decimal memory y)
        internal
        pure
        convertible(y)
        returns (SignedDecimal.signedDecimal memory)
    {
        SignedDecimal.signedDecimal memory t;
        t = x.divD(fromDecimal(y));
        return t;
    }

    /// @dev divide a SignedDecimal.signedDecimal by a uint256
    function divScalar(SignedDecimal.signedDecimal memory x, uint256 y)
        internal
        pure
        returns (SignedDecimal.signedDecimal memory)
    {
        require(_INT256_MAX >= y, ERROR_NON_CONVERTIBLE);
        SignedDecimal.signedDecimal memory t;
        t = x.divScalar(int256(y));
        return t;
    }
}

// File: contracts\utils\BlockContext.sol

pragma solidity ^0.6.12;

// wrap block.xxx functions for testing
// only support timestamp and number so far
abstract contract BlockContext {
    //◥◤◥◤◥◤◥◤◥◤◥◤◥◤◥◤ add state variables below ◥◤◥◤◥◤◥◤◥◤◥◤◥◤◥◤//

    //◢◣◢◣◢◣◢◣◢◣◢◣◢◣◢◣ add state variables above ◢◣◢◣◢◣◢◣◢◣◢◣◢◣◢◣//
    uint256[50] private __gap;

    function _blockTimestamp() internal view virtual returns (uint256) {
        return block.timestamp;
    }

    function _blockNumber() internal view virtual returns (uint256) {
        return block.number;
    }
}

// File: contracts\utils\Sqrt.sol

pragma solidity ^0.6.12;

library Sqrt {
    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    function sqrt(uint256 y) internal pure returns (uint256) {
        if (y > 3) {
            uint256 z = y;
            uint256 x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
            return z;
        } else if (y != 0) {
            return 1;
        } else {
            return 0;
        }
    }
}

// File: contracts\Exchange.sol

pragma solidity ^0.6.12;


contract Exchange is IExchange, OwnableUpgradeable, BlockContext {
    using SafeMathUpgradeable for uint256;
    using Decimal for Decimal.decimal;
    using SignedDecimal for SignedDecimal.signedDecimal;
    using MixedDecimal for SignedDecimal.signedDecimal;
    using Sqrt for uint256;

    //
    // CONSTANT
    //
    // because position decimal rounding error,
    // if the position size is less than IGNORABLE_DIGIT_FOR_SHUTDOWN, it's equal size is 0
    uint256 private constant IGNORABLE_DIGIT_FOR_SHUTDOWN = 100;

    // a margin to prevent from rounding when calc liquidity multiplier limit
    uint256 private constant MARGIN_FOR_LIQUIDITY_MIGRATION_ROUNDING = 1e9;

    //
    // EVENTS
    //
    event SwapInput(Dir dir, uint256 quoteAssetAmount, uint256 baseAssetAmount);
    event SwapOutput(Dir dir, uint256 quoteAssetAmount, uint256 baseAssetAmount);
    event FundingRateUpdated(int256 rate, uint256 underlyingPrice);
    event ReserveSnapshotted(uint256 quoteAssetReserve, uint256 baseAssetReserve, uint256 timestamp);
    event LiquidityChanged(uint256 quoteReserve, uint256 baseReserve, int256 cumulativeNotional);
    event CapChanged(uint256 maxHoldingBaseAsset, uint256 openInterestNotionalCap);
    event Shutdown(uint256 settlementPrice);
    event MoveAMMPrice(
        uint256 ammPrice,
        uint256 oraclePrice,
        uint256 adjustPrice,
        int256 MMLiquidity,
        int256 MMPNL,
        bool moved
    );

    //
    // MODIFIERS
    //
    modifier onlyOpen() {
        require(open, "exchange was closed");
        _;
    }

    modifier onlyClose() {
        require(open == false, "exchange was open");
        _;
    }

    modifier onlyCounterParty() {
        require(address(sakePerp) == _msgSender(), "caller is not counterParty");
        _;
    }

    modifier onlyMinter() {
        require(address(sakePerpVault) == _msgSender(), "caller is not minter");
        _;
    }

    //
    // enum and struct
    //
    struct ReserveSnapshot {
        Decimal.decimal quoteAssetReserve;
        Decimal.decimal baseAssetReserve;
        uint256 timestamp;
        uint256 blockNumber;
    }

    // internal usage
    enum QuoteAssetDir {QUOTE_IN, QUOTE_OUT}
    // internal usage
    enum TwapCalcOption {RESERVE_ASSET, INPUT_ASSET}

    // To record current base/quote asset to calculate TWAP

    struct TwapInputAsset {
        Dir dir;
        Decimal.decimal assetAmount;
        QuoteAssetDir inOrOut;
    }

    struct TwapPriceCalcParams {
        TwapCalcOption opt;
        uint256 snapshotIndex;
        TwapInputAsset asset;
    }

    //**********************************************************//
    //    The below state variables can not change the order    //
    //**********************************************************//

    // update during every swap and used when shutting exchange down
    SignedDecimal.signedDecimal public totalPositionSize;

    // latest funding rate = ((twap market price - twap oracle price) / twap oracle price) / 24
    SignedDecimal.signedDecimal public fundingRate;
    SignedDecimal.signedDecimal private cumulativeNotional;
    SignedDecimal.signedDecimal private mmCumulativeNotional;

    Decimal.decimal private settlementPrice;
    Decimal.decimal public override tradeLimitRatio;
    Decimal.decimal public quoteAssetReserve;
    Decimal.decimal public baseAssetReserve;
    Decimal.decimal public override fluctuationLimitRatio;

    // owner can update
    Decimal.decimal public override priceAdjustRatio;

    // snapshot of amm reserve when change liquidity's invariant
    LiquidityChangedSnapshot[] private liquidityChangedSnapshots;

    uint256 public spotPriceTwapInterval;
    uint256 public override fundingPeriod;
    uint256 public fundingBufferPeriod;
    uint256 public nextFundingTime;
    bytes32 public override priceFeedKey;
    ReserveSnapshot[] public reserveSnapshots;

    ISakePerpVault public sakePerpVault;
    IERC20Upgradeable public override quoteAsset;
    IPriceFeed public priceFeed;
    ISakePerp public sakePerp;
    bool public override open;
    uint256 public lastMoveAmmPriceTime;
    Decimal.decimal public oraclePriceSpreadLimit;
    address public mover;
    IExchangeState public override exchangeState;

    //**********************************************************//
    //    The above state variables can not change the order    //
    //**********************************************************//

    //◥◤◥◤◥◤◥◤◥◤◥◤◥◤◥◤ add state variables below ◥◤◥◤◥◤◥◤◥◤◥◤◥◤◥◤//

    //◢◣◢◣◢◣◢◣◢◣◢◣◢◣◢◣ add state variables above ◢◣◢◣◢◣◢◣◢◣◢◣◢◣◢◣//
    uint256[50] private __gap;

    //
    // FUNCTIONS
    //
    function initialize(
        uint256 _quoteAssetReserve,
        uint256 _baseAssetReserve,
        uint256 _tradeLimitRatio,
        uint256 _fundingPeriod,
        IPriceFeed _priceFeed,
        ISakePerp _sakePerp,
        ISakePerpVault _sakePerpVault,
        bytes32 _priceFeedKey,
        address _quoteAsset,
        uint256 _fluctuationLimitRatio,
        uint256 _priceAdjustRatio,
        IExchangeState _exchangeState
    ) public initializer {
        require(
            _quoteAssetReserve != 0 &&
                _tradeLimitRatio != 0 &&
                _baseAssetReserve != 0 &&
                _fundingPeriod != 0 &&
                address(_priceFeed) != address(0) &&
                address(_sakePerp) != address(0) &&
                address(_sakePerpVault) != address(0) &&
                address(_exchangeState) != address(0) &&
                _quoteAsset != address(0),
            "invalid input"
        );
        __Ownable_init();

        quoteAssetReserve = Decimal.decimal(_quoteAssetReserve);
        baseAssetReserve = Decimal.decimal(_baseAssetReserve);
        tradeLimitRatio = Decimal.decimal(_tradeLimitRatio);
        priceAdjustRatio = Decimal.decimal(_priceAdjustRatio);
        fluctuationLimitRatio = Decimal.decimal(_fluctuationLimitRatio);
        fundingPeriod = _fundingPeriod;
        fundingBufferPeriod = _fundingPeriod.div(2);
        spotPriceTwapInterval = 1 hours;
        priceFeedKey = _priceFeedKey;
        quoteAsset = IERC20Upgradeable(_quoteAsset);
        priceFeed = _priceFeed;
        sakePerp = _sakePerp;
        sakePerpVault = _sakePerpVault;
        exchangeState = _exchangeState;
        oraclePriceSpreadLimit = Decimal.decimal(3 * 10**17);
        mover = _msgSender();

        sakePerpVault.setHighRiskLiquidityWeight(address(this), 400);
        sakePerpVault.setMaxLoss(address(this), ISakePerpVaultTypes.Risk.HIGH, 50);
        sakePerpVault.setMaxLoss(address(this), ISakePerpVaultTypes.Risk.LOW, 25);

        liquidityChangedSnapshots.push(
            LiquidityChangedSnapshot({
                cumulativeNotional: SignedDecimal.zero(),
                baseAssetReserve: baseAssetReserve,
                quoteAssetReserve: quoteAssetReserve,
                totalPositionSize: SignedDecimal.zero()
            })
        );
        reserveSnapshots.push(ReserveSnapshot(quoteAssetReserve, baseAssetReserve, _blockTimestamp(), _blockNumber()));
        emit ReserveSnapshotted(quoteAssetReserve.toUint(), baseAssetReserve.toUint(), _blockTimestamp());
    }

    /**
     * @notice mint MLP for MM
     * @dev only sakePerpVault can call this function
     */
    function mint(
        ISakePerpVaultTypes.Risk _risk,
        address account,
        uint256 amount
    ) external override onlyOpen onlyMinter {
        exchangeState.mint(_risk, account, amount);
    }

    /**
     * @notice burn MLP
     * @dev only sakePerpVault can call this function
     */
    function burn(
        ISakePerpVaultTypes.Risk _risk,
        address account,
        uint256 amount
    ) external override onlyMinter {
        exchangeState.burn(_risk, account, amount);
    }

    /**
     * @notice Swap your quote asset to base asset, the impact of the price MUST be less than `fluctuationLimitRatio`
     * @dev Only clearingHouse can call this function
     * @param _dir ADD_TO_AMM for long, REMOVE_FROM_AMM for short
     * @param _quoteAssetAmount quote asset amount
     * @param _baseAssetAmountLimit minimum base asset amount expected to get to prevent front running
     * @return base asset amount
     */
    function swapInput(
        Dir _dir,
        Decimal.decimal calldata _quoteAssetAmount,
        Decimal.decimal calldata _baseAssetAmountLimit
    ) external override onlyOpen onlyCounterParty returns (Decimal.decimal memory) {
        if (_quoteAssetAmount.toUint() == 0) {
            return Decimal.zero();
        }
        if (_dir == Dir.REMOVE_FROM_AMM) {
            require(
                quoteAssetReserve.mulD(tradeLimitRatio).toUint() >= _quoteAssetAmount.toUint(),
                "over trading limit"
            );
        }

        Decimal.decimal memory baseAssetAmount = getInputPrice(_dir, _quoteAssetAmount);
        // If LONG, exchanged base amount should be more than _baseAssetAmountLimit,
        // otherwise(SHORT), exchanged base amount should be less than _baseAssetAmountLimit.
        // In SHORT case, more position means more debt so should not be larger than _baseAssetAmountLimit
        if (_baseAssetAmountLimit.toUint() != 0) {
            if (_dir == Dir.ADD_TO_AMM) {
                require(baseAssetAmount.toUint() >= _baseAssetAmountLimit.toUint(), "Less than minimal base token");
            } else {
                require(baseAssetAmount.toUint() <= _baseAssetAmountLimit.toUint(), "More than maximal base token");
            }
        }

        updateReserve(_dir, _quoteAssetAmount, baseAssetAmount, false);
        emit SwapInput(_dir, _quoteAssetAmount.toUint(), baseAssetAmount.toUint());
        return baseAssetAmount;
    }

    /**
     * @notice swap your base asset to quote asset; the impact of the price can be restricted with fluctuationLimitRatio
     * @dev only clearingHouse can call this function
     * @param _dir ADD_TO_AMM for short, REMOVE_FROM_AMM for long, opposite direction from swapInput
     * @param _baseAssetAmount base asset amount
     * @param _quoteAssetAmountLimit limit of quote asset amount; for slippage protection
     * @param _skipFluctuationCheck false for checking fluctuationLimitRatio; true for no limit, only when closePosition()
     * @return quote asset amount
     */
    function swapOutput(
        Dir _dir,
        Decimal.decimal calldata _baseAssetAmount,
        Decimal.decimal calldata _quoteAssetAmountLimit,
        bool _skipFluctuationCheck
    ) external override onlyOpen onlyCounterParty returns (Decimal.decimal memory) {
        return implSwapOutput(_dir, _baseAssetAmount, _quoteAssetAmountLimit, _skipFluctuationCheck);
    }

    /**
     * @notice update funding rate
     * @dev only allow to update while reaching `nextFundingTime`
     * @return premium fraction of this period in 18 digits
     */
    function settleFunding() external override onlyOpen onlyCounterParty returns (SignedDecimal.signedDecimal memory) {
        require(_blockTimestamp() >= nextFundingTime, "settle funding too early");
        SignedDecimal.signedDecimal memory premiumFraction = SignedDecimal.zero();
        Decimal.decimal memory underlyingPrice = getUnderlyingTwapPrice(spotPriceTwapInterval);

        // if AMM price has been moved before fundingTime, no need to this funding
        if (lastMoveAmmPriceTime.add(fundingPeriod) < nextFundingTime) {
            // premium = twapMarketPrice - twapIndexPrice
            // timeFraction = fundingPeriod(1 hour) / 1 day
            // premiumFraction = premium * timeFraction
            SignedDecimal.signedDecimal memory premium =
                MixedDecimal.fromDecimal(getTwapPrice(spotPriceTwapInterval)).subD(underlyingPrice);
            premiumFraction = premium.mulScalar(fundingPeriod).divScalar(int256(1 days));
        }

        // update funding rate = premiumFraction / twapIndexPrice
        updateFundingRate(premiumFraction, underlyingPrice);

        // in order to prevent multiple funding settlement during very short time after network congestion
        uint256 minNextValidFundingTime = _blockTimestamp().add(fundingBufferPeriod);

        // floor((nextFundingTime + fundingPeriod) / 3600) * 3600
        uint256 nextFundingTimeOnHourStart = nextFundingTime.add(fundingPeriod).div(1 hours).mul(1 hours);

        // max(nextFundingTimeOnHourStart, minNextValidFundingTime)
        nextFundingTime = nextFundingTimeOnHourStart > minNextValidFundingTime
            ? nextFundingTimeOnHourStart
            : minNextValidFundingTime;

        return premiumFraction;
    }

    function migrateLiquidity(
        Decimal.decimal calldata _liquidityMultiplier,
        Decimal.decimal calldata _fluctuationLimitRatio
    ) external override onlyOwner {
        require(_liquidityMultiplier.toUint() != Decimal.one().toUint(), "multiplier can't be 1");

        // check liquidity multiplier limit, have lower bound if position size is positive for now.
        checkLiquidityMultiplierLimit(totalPositionSize, _liquidityMultiplier);

        // #53 fix sandwich attack during liquidity migration
        checkFluctuationLimit(_fluctuationLimitRatio);

        // get current reserve values
        Decimal.decimal memory quoteAssetBeforeAddingLiquidity = quoteAssetReserve;
        Decimal.decimal memory baseAssetBeforeAddingLiquidity = baseAssetReserve;
        SignedDecimal.signedDecimal memory totalPositionSizeBefore = totalPositionSize;

        // migrate liquidity
        quoteAssetReserve = quoteAssetBeforeAddingLiquidity.mulD(_liquidityMultiplier);
        baseAssetReserve = baseAssetBeforeAddingLiquidity.mulD(_liquidityMultiplier);

        totalPositionSize = calcBaseAssetAfterLiquidityMigration(
            totalPositionSizeBefore,
            quoteAssetBeforeAddingLiquidity,
            baseAssetBeforeAddingLiquidity
        );

        // update snapshot
        liquidityChangedSnapshots.push(
            LiquidityChangedSnapshot({
                cumulativeNotional: cumulativeNotional,
                quoteAssetReserve: quoteAssetReserve,
                baseAssetReserve: baseAssetReserve,
                totalPositionSize: totalPositionSize
            })
        );

        emit LiquidityChanged(quoteAssetReserve.toUint(), baseAssetReserve.toUint(), cumulativeNotional.toInt());
    }

    function calcBaseAssetAfterLiquidityMigration(
        SignedDecimal.signedDecimal memory _baseAssetAmount,
        Decimal.decimal memory _fromQuoteReserve,
        Decimal.decimal memory _fromBaseReserve
    ) public view override returns (SignedDecimal.signedDecimal memory) {
        if (_baseAssetAmount.toUint() == 0) {
            return _baseAssetAmount;
        }

        bool isPositiveValue = _baseAssetAmount.toInt() > 0 ? true : false;

        // measure the trader position's notional value on the old curve
        // (by simulating closing the position)
        Decimal.decimal memory posNotional =
            getOutputPriceWithReserves(
                isPositiveValue ? Dir.ADD_TO_AMM : Dir.REMOVE_FROM_AMM,
                _baseAssetAmount.abs(),
                _fromQuoteReserve,
                _fromBaseReserve
            );

        // calculate and apply the required size on the new curve
        SignedDecimal.signedDecimal memory newBaseAsset =
            MixedDecimal.fromDecimal(
                getInputPrice(isPositiveValue ? Dir.REMOVE_FROM_AMM : Dir.ADD_TO_AMM, posNotional)
            );
        return newBaseAsset.mulScalar(isPositiveValue ? 1 : int256(-1));
    }

    /**
     * @notice shutdown exchange
     * @dev only owner can call this function
     */
    function shutdown() external override onlyOwner {
        sakePerpVault.modifyLiquidity();
        LiquidityChangedSnapshot memory latestLiquiditySnapshot = getLatestLiquidityChangedSnapshots();

        // get last liquidity changed history to calc new quote/base reserve
        Decimal.decimal memory previousK =
            latestLiquiditySnapshot.baseAssetReserve.mulD(latestLiquiditySnapshot.quoteAssetReserve);
        SignedDecimal.signedDecimal memory lastInitBaseReserveInNewCurve =
            latestLiquiditySnapshot.totalPositionSize.addD(latestLiquiditySnapshot.baseAssetReserve);
        SignedDecimal.signedDecimal memory lastInitQuoteReserveInNewCurve =
            MixedDecimal.fromDecimal(previousK).divD(lastInitBaseReserveInNewCurve);

        // settlementPrice = SUM(Open Position Notional Value) / SUM(Position Size)
        // `Open Position Notional Value` = init quote reserve - current quote reserve
        // `Position Size` = init base reserve - current base reserve
        SignedDecimal.signedDecimal memory positionNotionalValue =
            lastInitQuoteReserveInNewCurve.subD(quoteAssetReserve);

        // if total position size less than IGNORABLE_DIGIT_FOR_SHUTDOWN, treat it as 0 positions due to rounding error
        if (totalPositionSize.toUint() > IGNORABLE_DIGIT_FOR_SHUTDOWN) {
            settlementPrice = positionNotionalValue.abs().divD(totalPositionSize.abs());
        }

        open = false;
        emit Shutdown(settlementPrice.toUint());
    }

    /**
     * @notice set counter party
     * @dev only owner can call this function
     * @param _counterParty address of counter party
     */
    function setCounterParty(address _counterParty) external onlyOwner {
        sakePerp = ISakePerp(_counterParty);
    }

    /**
     * @notice set minter
     * @dev only owner can call this function
     * @param _minter address of minter
     */
    function setMinter(address _minter) external onlyOwner {
        sakePerpVault = ISakePerpVault(_minter);
    }

    /**
     * @notice set fluctuation limit rate. Default value is `1 / max leverage`
     * @dev only owner can call this function
     * @param _fluctuationLimitRatio fluctuation limit rate in 18 digits, 0 means skip the checking
     */
    function setFluctuationLimitRatio(Decimal.decimal memory _fluctuationLimitRatio) public onlyOwner {
        fluctuationLimitRatio = _fluctuationLimitRatio;
    }

    /**
     * @notice set time interval for twap calculation, default is 1 hour
     * @dev only owner can call this function
     * @param _interval time interval in seconds
     */
    function setSpotPriceTwapInterval(uint256 _interval) external onlyOwner {
        require(_interval != 0, "can not set interval to 0");
        spotPriceTwapInterval = _interval;
    }

    /**
     * @notice set `open` flag. Amm is open to trade if `open` is true. Default is false.
     * @dev only owner can call this function
     * @param _open open to trade is true, otherwise is false.
     */
    function setOpen(bool _open) external onlyOwner {
        if (open == _open) return;

        open = _open;
        if (_open) {
            nextFundingTime = _blockTimestamp().add(fundingPeriod).div(1 hours).mul(1 hours);
        }
    }

    /**
     * @notice set new price adjust ratio
     * @dev only owner can call
     * @param _priceAdjustRatio new price adjust spread in 18 digits
     */
    function setPriceAdjustRatio(Decimal.decimal memory _priceAdjustRatio) public onlyOwner {
        require(_priceAdjustRatio.cmp(Decimal.one()) <= 0, "invalid ratio");
        priceAdjustRatio = _priceAdjustRatio;
    }

    /**
     * @notice set price feed address
     * @param _priceFeed new price feed address
     */
    function setPriceFeed(address _priceFeed) public override onlyOwner {
        require(_priceFeed != address(0), "invalid address");
        priceFeed = IPriceFeed(_priceFeed);
    }

    /**
     * @notice set oracle price spread limitation
     * @param _limit new limitation
     */
    function setOraclePriceSpreadLimit(Decimal.decimal memory _limit) public onlyOwner {
        oraclePriceSpreadLimit = _limit;
    }

    /**
     * @notice set oracle price mover
     * @param _newMover new mover
     */
    function setMover(address _newMover) public onlyOwner {
        require(_newMover != address(0), "invalid address");
        mover = _newMover;
    }

    /**
     * @notice set exchange state address
     * @param _exchangeState new exchange state address
     */
    function setExchangeState(address _exchangeState) public onlyOwner {
        require(_exchangeState != address(0), "invalid address");
        exchangeState = IExchangeState(_exchangeState);
    }

    //
    // VIEW FUNCTIONS
    //

    /**
     * @notice get input twap amount.
     * returns how many base asset you will get with the input quote amount based on twap price.
     * @param _dir ADD_TO_AMM for long, REMOVE_FROM_AMM for short.
     * @param _quoteAssetAmount quote asset amount
     * @return base asset amount
     */
    function getInputTwap(Dir _dir, Decimal.decimal memory _quoteAssetAmount)
        public
        view
        override
        returns (Decimal.decimal memory)
    {
        return implGetInputAssetTwapPrice(_dir, _quoteAssetAmount, QuoteAssetDir.QUOTE_IN, 15 minutes);
    }

    /**
     * @notice get output twap amount.
     * return how many quote asset you will get with the input base amount on twap price.
     * @param _dir ADD_TO_AMM for short, REMOVE_FROM_AMM for long, opposite direction from `getInputTwap`.
     * @param _baseAssetAmount base asset amount
     * @return quote asset amount
     */
    function getOutputTwap(Dir _dir, Decimal.decimal memory _baseAssetAmount)
        public
        view
        override
        returns (Decimal.decimal memory)
    {
        return implGetInputAssetTwapPrice(_dir, _baseAssetAmount, QuoteAssetDir.QUOTE_OUT, 15 minutes);
    }

    /**
     * @notice get input amount. returns how many base asset you will get with the input quote amount.
     * @param _dir ADD_TO_AMM for long, REMOVE_FROM_AMM for short.
     * @param _quoteAssetAmount quote asset amount
     * @return base asset amount
     */
    function getInputPrice(Dir _dir, Decimal.decimal memory _quoteAssetAmount)
        public
        view
        override
        returns (Decimal.decimal memory)
    {
        return getInputPriceWithReserves(_dir, _quoteAssetAmount, quoteAssetReserve, baseAssetReserve);
    }

    /**
     * @notice get output price. return how many quote asset you will get with the input base amount
     * @param _dir ADD_TO_AMM for short, REMOVE_FROM_AMM for long, opposite direction from `getInput`.
     * @param _baseAssetAmount base asset amount
     * @return quote asset amount
     */
    function getOutputPrice(Dir _dir, Decimal.decimal memory _baseAssetAmount)
        public
        view
        override
        returns (Decimal.decimal memory)
    {
        return getOutputPriceWithReserves(_dir, _baseAssetAmount, quoteAssetReserve, baseAssetReserve);
    }

    /**
     * @notice get underlying price provided by oracle
     * @return underlying price
     */
    function getUnderlyingPrice() public view override returns (Decimal.decimal memory) {
        return Decimal.decimal(priceFeed.getPrice(priceFeedKey));
    }

    /**
     * @notice get underlying twap price provided by oracle
     * @return underlying price
     */
    function getUnderlyingTwapPrice(uint256 _intervalInSeconds) public view returns (Decimal.decimal memory) {
        return Decimal.decimal(priceFeed.getTwapPrice(priceFeedKey, _intervalInSeconds));
    }

    /**
     * @notice get spot price based on current quote/base asset reserve.
     * @return spot price
     */
    function getSpotPrice() public view override returns (Decimal.decimal memory) {
        return quoteAssetReserve.divD(baseAssetReserve);
    }

    /**
     * @notice get twap price
     */
    function getTwapPrice(uint256 _intervalInSeconds) public view returns (Decimal.decimal memory) {
        return implGetReserveTwapPrice(_intervalInSeconds);
    }

    /**
     * @notice get current quote/base asset reserve.
     * @return (quote asset reserve, base asset reserve)
     */
    function getReserve() external view override returns (Decimal.decimal memory, Decimal.decimal memory) {
        return (quoteAssetReserve, baseAssetReserve);
    }

    //@audit - no one use this anymore, can be remove (@wraecca).
    // If we remove this, we should make reserveSnapshots private.
    // If we need reserveSnapshots, should keep this. (@Kimi)
    function getSnapshotLen() external view returns (uint256) {
        return reserveSnapshots.length;
    }

    function getLiquidityHistoryLength() external view override returns (uint256) {
        return liquidityChangedSnapshots.length;
    }

    function getCumulativeNotional() external view override returns (SignedDecimal.signedDecimal memory) {
        return cumulativeNotional;
    }

    function getLatestLiquidityChangedSnapshots() public view returns (LiquidityChangedSnapshot memory) {
        return liquidityChangedSnapshots[liquidityChangedSnapshots.length.sub(1)];
    }

    function getLiquidityChangedSnapshots(uint256 i) external view override returns (LiquidityChangedSnapshot memory) {
        require(i < liquidityChangedSnapshots.length, "incorrect index");
        return liquidityChangedSnapshots[i];
    }

    function getSettlementPrice() external view override returns (Decimal.decimal memory) {
        return settlementPrice;
    }

    function getMaxHoldingBaseAsset() external view override returns (Decimal.decimal memory) {
        return exchangeState.getMaxHoldingBaseAsset();
    }

    function getOpenInterestNotionalCap() external view override returns (Decimal.decimal memory) {
        return exchangeState.getOpenInterestNotionalCap();
    }

    function initMarginRatio() external view override returns (Decimal.decimal memory) {
        return exchangeState.initMarginRatio();
    }

    function maintenanceMarginRatio() external view override returns (Decimal.decimal memory) {
        return exchangeState.maintenanceMarginRatio();
    }

    function liquidationFeeRatio() external view override returns (Decimal.decimal memory) {
        return exchangeState.liquidationFeeRatio();
    }

    function maxLiquidationFee() external view override returns (Decimal.decimal memory) {
        return exchangeState.maxLiquidationFee();
    }

    function spreadRatio() external view override returns (Decimal.decimal memory) {
        return exchangeState.spreadRatio();
    }

    function getTotalPositionSize() external view override returns (SignedDecimal.signedDecimal memory) {
        return totalPositionSize;
    }

    function isOverSpreadLimit() external view override returns (bool) {
        Decimal.decimal memory oraclePrice = getUnderlyingPrice();
        require(oraclePrice.toUint() > 0, "underlying price is 0");
        Decimal.decimal memory marketPrice = getSpotPrice();
        Decimal.decimal memory oracleSpreadRatioAbs =
            MixedDecimal.fromDecimal(marketPrice).subD(oraclePrice).divD(oraclePrice).abs();

        return oracleSpreadRatioAbs.toUint() >= exchangeState.maxOracleSpreadRatio().toUint() ? true : false;
    }

    /**
     * @notice calculate spread fee by input quoteAssetAmount
     * @param _quoteAssetAmount quoteAssetAmount
     * @return total tx fee
     */
    function calcFee(Decimal.decimal calldata _quoteAssetAmount)
        external
        view
        override
        returns (Decimal.decimal memory)
    {
        return exchangeState.calcFee(_quoteAssetAmount);
    }

    function getInputPriceWithReserves(
        Dir _dir,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) public view override returns (Decimal.decimal memory) {
        return
            exchangeState.getInputPriceWithReserves(
                _dir,
                _quoteAssetAmount,
                _quoteAssetPoolAmount,
                _baseAssetPoolAmount
            );
    }

    function getOutputPriceWithReserves(
        Dir _dir,
        Decimal.decimal memory _baseAssetAmount,
        Decimal.decimal memory _quoteAssetPoolAmount,
        Decimal.decimal memory _baseAssetPoolAmount
    ) public view override returns (Decimal.decimal memory) {
        return
            exchangeState.getOutputPriceWithReserves(
                _dir,
                _baseAssetAmount,
                _quoteAssetPoolAmount,
                _baseAssetPoolAmount
            );
    }

    //
    // INTERNAL FUNCTIONS
    //
    // update funding rate = premiumFraction / twapIndexPrice
    function updateFundingRate(
        SignedDecimal.signedDecimal memory _premiumFraction,
        Decimal.decimal memory _underlyingPrice
    ) private {
        fundingRate = _premiumFraction.divD(_underlyingPrice);
        emit FundingRateUpdated(fundingRate.toInt(), _underlyingPrice.toUint());
    }

    function addReserveSnapshot() internal {
        uint256 currentBlock = _blockNumber();
        ReserveSnapshot storage latestSnapshot = reserveSnapshots[reserveSnapshots.length - 1];
        // update values in snapshot if in the same block
        if (currentBlock == latestSnapshot.blockNumber) {
            latestSnapshot.quoteAssetReserve = quoteAssetReserve;
            latestSnapshot.baseAssetReserve = baseAssetReserve;
        } else {
            reserveSnapshots.push(
                ReserveSnapshot(quoteAssetReserve, baseAssetReserve, _blockTimestamp(), currentBlock)
            );
        }
        emit ReserveSnapshotted(quoteAssetReserve.toUint(), baseAssetReserve.toUint(), _blockTimestamp());
    }

    function implSwapOutput(
        Dir _dir,
        Decimal.decimal memory _baseAssetAmount,
        Decimal.decimal memory _quoteAssetAmountLimit,
        bool _skipFluctuationCheck
    ) internal returns (Decimal.decimal memory) {
        if (_baseAssetAmount.toUint() == 0) {
            return Decimal.zero();
        }

        // positionSize may little than real position size because of migtrate liquidity
        if (_dir == Dir.REMOVE_FROM_AMM) {
            require(baseAssetReserve.mulD(tradeLimitRatio).toUint() >= _baseAssetAmount.toUint(), "over trading limit");
        }

        Decimal.decimal memory quoteAssetAmount = getOutputPrice(_dir, _baseAssetAmount);
        // If SHORT, exchanged quote amount should be less than _quoteAssetAmountLimit,
        // otherwise(LONG), exchanged base amount should be more than _quoteAssetAmountLimit.
        // In the SHORT case, more quote assets means more payment so should not be more than _quoteAssetAmountLimit
        if (_quoteAssetAmountLimit.toUint() != 0) {
            if (_dir == Dir.ADD_TO_AMM) {
                // SHORT
                require(quoteAssetAmount.toUint() >= _quoteAssetAmountLimit.toUint(), "Less than minimal quote token");
            } else {
                // LONG
                require(quoteAssetAmount.toUint() <= _quoteAssetAmountLimit.toUint(), "More than maximal quote token");
            }
        }

        // If the price impact of one single tx is larger than priceFluctuation, skip the check
        // only for liquidate()
        if (!_skipFluctuationCheck) {
            _skipFluctuationCheck = isSingleTxOverFluctuation(_dir, quoteAssetAmount, _baseAssetAmount);
        }

        updateReserve(
            _dir == Dir.ADD_TO_AMM ? Dir.REMOVE_FROM_AMM : Dir.ADD_TO_AMM,
            quoteAssetAmount,
            _baseAssetAmount,
            _skipFluctuationCheck
        );

        emit SwapOutput(_dir, quoteAssetAmount.toUint(), _baseAssetAmount.toUint());
        return quoteAssetAmount;
    }

    function updateReserve(
        Dir _dir,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _baseAssetAmount,
        bool _skipFluctuationCheck
    ) internal {
        if (_dir == Dir.ADD_TO_AMM) {
            quoteAssetReserve = quoteAssetReserve.addD(_quoteAssetAmount);
            baseAssetReserve = baseAssetReserve.subD(_baseAssetAmount);
            totalPositionSize = totalPositionSize.addD(_baseAssetAmount);
            cumulativeNotional = cumulativeNotional.addD(_quoteAssetAmount);
        } else {
            quoteAssetReserve = quoteAssetReserve.subD(_quoteAssetAmount);
            baseAssetReserve = baseAssetReserve.addD(_baseAssetAmount);
            totalPositionSize = totalPositionSize.subD(_baseAssetAmount);
            cumulativeNotional = cumulativeNotional.subD(_quoteAssetAmount);
        }

        // check if it's over fluctuationLimitRatio
        if (!_skipFluctuationCheck) {
            checkFluctuationLimit(fluctuationLimitRatio);
        }

        // addReserveSnapshot must be after checking price fluctuation
        addReserveSnapshot();
    }

    function implGetInputAssetTwapPrice(
        Dir _dir,
        Decimal.decimal memory _assetAmount,
        QuoteAssetDir _inOut,
        uint256 _interval
    ) internal view returns (Decimal.decimal memory) {
        TwapPriceCalcParams memory params;
        params.opt = TwapCalcOption.INPUT_ASSET;
        params.snapshotIndex = reserveSnapshots.length.sub(1);
        params.asset.dir = _dir;
        params.asset.assetAmount = _assetAmount;
        params.asset.inOrOut = _inOut;
        return calcTwap(params, _interval);
    }

    function implGetReserveTwapPrice(uint256 _interval) internal view returns (Decimal.decimal memory) {
        TwapPriceCalcParams memory params;
        params.opt = TwapCalcOption.RESERVE_ASSET;
        params.snapshotIndex = reserveSnapshots.length.sub(1);
        return calcTwap(params, _interval);
    }

    function calcTwap(TwapPriceCalcParams memory _params, uint256 _interval)
        internal
        view
        returns (Decimal.decimal memory)
    {
        Decimal.decimal memory currentPrice = getPriceWithSpecificSnapshot(_params);
        if (_interval == 0) {
            return currentPrice;
        }

        uint256 baseTimestamp = _blockTimestamp().sub(_interval);
        ReserveSnapshot memory currentSnapshot = reserveSnapshots[_params.snapshotIndex];
        // return the latest snapshot price directly
        // if only one snapshot or the timestamp of latest snapshot is earlier than asking for
        if (reserveSnapshots.length == 1 || currentSnapshot.timestamp <= baseTimestamp) {
            return currentPrice;
        }

        uint256 previousTimestamp = currentSnapshot.timestamp;
        uint256 period = _blockTimestamp().sub(previousTimestamp);
        Decimal.decimal memory weightedPrice = currentPrice.mulScalar(period);
        while (true) {
            // if snapshot history is too short
            if (_params.snapshotIndex == 0) {
                return weightedPrice.divScalar(period);
            }

            _params.snapshotIndex = _params.snapshotIndex.sub(1);
            currentSnapshot = reserveSnapshots[_params.snapshotIndex];
            currentPrice = getPriceWithSpecificSnapshot(_params);

            // check if current round timestamp is earlier than target timestamp
            if (currentSnapshot.timestamp <= baseTimestamp) {
                // weighted time period will be (target timestamp - previous timestamp). For example,
                // now is 1000, _interval is 100, then target timestamp is 900. If timestamp of current round is 970,
                // and timestamp of NEXT round is 880, then the weighted time period will be (970 - 900) = 70,
                // instead of (970 - 880)
                weightedPrice = weightedPrice.addD(currentPrice.mulScalar(previousTimestamp.sub(baseTimestamp)));
                break;
            }

            uint256 timeFraction = previousTimestamp.sub(currentSnapshot.timestamp);
            weightedPrice = weightedPrice.addD(currentPrice.mulScalar(timeFraction));
            period = period.add(timeFraction);
            previousTimestamp = currentSnapshot.timestamp;
        }
        return weightedPrice.divScalar(_interval);
    }

    function getPriceWithSpecificSnapshot(TwapPriceCalcParams memory params)
        internal
        view
        virtual
        returns (Decimal.decimal memory)
    {
        ReserveSnapshot memory snapshot = reserveSnapshots[params.snapshotIndex];

        // RESERVE_ASSET means price comes from quoteAssetReserve/baseAssetReserve
        // INPUT_ASSET means getInput/Output price with snapshot's reserve
        if (params.opt == TwapCalcOption.RESERVE_ASSET) {
            return snapshot.quoteAssetReserve.divD(snapshot.baseAssetReserve);
        } else if (params.opt == TwapCalcOption.INPUT_ASSET) {
            if (params.asset.assetAmount.toUint() == 0) {
                return Decimal.zero();
            }
            if (params.asset.inOrOut == QuoteAssetDir.QUOTE_IN) {
                return
                    getInputPriceWithReserves(
                        params.asset.dir,
                        params.asset.assetAmount,
                        snapshot.quoteAssetReserve,
                        snapshot.baseAssetReserve
                    );
            } else if (params.asset.inOrOut == QuoteAssetDir.QUOTE_OUT) {
                return
                    getOutputPriceWithReserves(
                        params.asset.dir,
                        params.asset.assetAmount,
                        snapshot.quoteAssetReserve,
                        snapshot.baseAssetReserve
                    );
            }
        }
        revert("not supported option");
    }

    function isSingleTxOverFluctuation(
        Dir _dir,
        Decimal.decimal memory _quoteAssetAmount,
        Decimal.decimal memory _baseAssetAmount
    ) internal view returns (bool) {
        Decimal.decimal memory priceAfterReserveUpdated =
            (_dir == Dir.ADD_TO_AMM)
                ? quoteAssetReserve.subD(_quoteAssetAmount).divD(baseAssetReserve.addD(_baseAssetAmount))
                : quoteAssetReserve.addD(_quoteAssetAmount).divD(baseAssetReserve.subD(_baseAssetAmount));
        return
            isOverFluctuationLimit(
                priceAfterReserveUpdated,
                fluctuationLimitRatio,
                reserveSnapshots[reserveSnapshots.length.sub(1)]
            );
    }

    function checkFluctuationLimit(Decimal.decimal memory _fluctuationLimitRatio) internal view {
        // Skip the check if the limit is 0
        if (_fluctuationLimitRatio.toUint() > 0) {
            uint256 len = reserveSnapshots.length;
            ReserveSnapshot memory latestSnapshot = reserveSnapshots[len - 1];

            // if the latest snapshot is the same as current block, get the previous one
            if (latestSnapshot.blockNumber == _blockNumber() && len > 1) {
                latestSnapshot = reserveSnapshots[len - 2];
            }

            require(
                !isOverFluctuationLimit(
                    quoteAssetReserve.divD(baseAssetReserve),
                    _fluctuationLimitRatio,
                    latestSnapshot
                ),
                "price is over fluctuation limit"
            );
        }
    }

    function checkLiquidityMultiplierLimit(
        SignedDecimal.signedDecimal memory _positionSize,
        Decimal.decimal memory _liquidityMultiplier
    ) internal view {
        // have lower bound when position size is long
        if (_positionSize.toInt() > 0) {
            Decimal.decimal memory liquidityMultiplierLowerBound =
                _positionSize
                    .addD(Decimal.decimal(MARGIN_FOR_LIQUIDITY_MIGRATION_ROUNDING))
                    .divD(baseAssetReserve)
                    .abs();
            require(_liquidityMultiplier.cmp(liquidityMultiplierLowerBound) >= 0, "illegal liquidity multiplier");
        }
    }

    function isOverFluctuationLimit(
        Decimal.decimal memory _price,
        Decimal.decimal memory _fluctuationLimitRatio,
        ReserveSnapshot memory _snapshot
    ) internal pure returns (bool) {
        Decimal.decimal memory lastPrice = _snapshot.quoteAssetReserve.divD(_snapshot.baseAssetReserve);
        Decimal.decimal memory upperLimit = lastPrice.mulD(Decimal.one().addD(_fluctuationLimitRatio));
        Decimal.decimal memory lowerLimit = lastPrice.mulD(Decimal.one().subD(_fluctuationLimitRatio));

        if (_price.cmp(upperLimit) <= 0 && _price.cmp(lowerLimit) >= 0) {
            return false;
        }
        return true;
    }

    function moveAMMPriceToOracle(uint256 _oraclePrice, bytes32 _priceFeedKey) public override {
        require(mover == _msgSender() || address(priceFeed) == _msgSender(), "illegal operator");
        require(_oraclePrice > 0, "oracle price can't be zero");
        require(priceFeedKey == _priceFeedKey, "illegal price feed key");
        if (!open || priceAdjustRatio.toUint() == 0) return;

        Decimal.decimal memory oraclePrice = Decimal.decimal(_oraclePrice);
        Decimal.decimal memory AMMPrice = quoteAssetReserve.divD(baseAssetReserve);
        require(
            MixedDecimal.fromDecimal(oraclePrice).subD(AMMPrice).abs().cmp(oraclePriceSpreadLimit.mulD(AMMPrice)) <= 0,
            "invalid oracle price"
        );

        Decimal.decimal memory adjustPrice =
            MixedDecimal
                .fromDecimal(AMMPrice)
                .addD(MixedDecimal.fromDecimal(oraclePrice).subD(AMMPrice).mulD(priceAdjustRatio))
                .abs();

        // baseAssetReserve * oraclePrice * baseAssetReserve = invariant
        Decimal.decimal memory invariant = quoteAssetReserve.mulD(baseAssetReserve);
        uint256 basePow = invariant.divD(adjustPrice).toUint().mul(Decimal.one().toUint());
        Decimal.decimal memory _baseAssetReserve = Decimal.decimal(basePow.sqrt());
        Decimal.decimal memory _quoteAssetReserve = invariant.divD(_baseAssetReserve);

        SignedDecimal.signedDecimal memory MMPNL = getMMUnrealizedPNL(_baseAssetReserve, _quoteAssetReserve);
        SignedDecimal.signedDecimal memory MMLiquidity = sakePerpVault.getTotalMMAvailableLiquidity(address(this));
        Decimal.decimal memory MMCachedLiquidity = sakePerpVault.getTotalMMCachedLiquidity(address(this));

        // negative means MM can't pay for this price movement
        if (MMPNL.addD(MMLiquidity).addD(MMCachedLiquidity).isNegative()) {
            emit MoveAMMPrice(
                AMMPrice.toUint(),
                _oraclePrice,
                adjustPrice.toUint(),
                MMLiquidity.toInt(),
                MMPNL.toInt(),
                false
            );
        } else {
            SignedDecimal.signedDecimal memory mmNotional =
                MixedDecimal.fromDecimal(_quoteAssetReserve).subD(quoteAssetReserve);
            mmCumulativeNotional = mmCumulativeNotional.addD(mmNotional);
            cumulativeNotional = cumulativeNotional.addD(mmNotional);
            baseAssetReserve = _baseAssetReserve;
            quoteAssetReserve = _quoteAssetReserve;
            lastMoveAmmPriceTime = _blockTimestamp();

            addReserveSnapshot();
            sakePerpVault.modifyLiquidity();

            emit MoveAMMPrice(
                AMMPrice.toUint(),
                _oraclePrice,
                adjustPrice.toUint(),
                MMLiquidity.addD(MMCachedLiquidity).toInt(),
                MMPNL.toInt(),
                true
            );
        }
    }

    /**
     * @notice get MM unrealized PNL
     */
    function getMMUnrealizedPNL(Decimal.decimal memory _baseAssetReserve, Decimal.decimal memory _quoteAssetReserve)
        public
        view
        override
        returns (SignedDecimal.signedDecimal memory)
    {
        // MMUnrealizedPNL = - (closeLongQuoteAssetAmout - openLongQuoteAssetAmout + openShortQuoteAssetAmout - closeShortQuoteAssetAmout)
        // MMUnrealizedPNL = openLongQuoteAssetAmout - openShortQuoteAssetAmout + closeShortQuoteAssetAmout - closeLongQuoteAssetAmout
        // cumulativeNotional = openLongQuoteAssetAmout - openShortQuoteAssetAmout
        // MMUnrealizedPNL = cumulativeNotional + closeShortQuoteAssetAmout - closeLongQuoteAssetAmout
        SignedDecimal.signedDecimal memory detalCloseAmount;
        if (totalPositionSize.isNegative()) {
            detalCloseAmount = MixedDecimal.fromDecimal(
                getOutputPriceWithReserves(
                    Dir.REMOVE_FROM_AMM,
                    totalPositionSize.abs(),
                    _quoteAssetReserve,
                    _baseAssetReserve
                )
            );
        } else {
            detalCloseAmount = MixedDecimal
                .fromDecimal(
                getOutputPriceWithReserves(
                    Dir.ADD_TO_AMM,
                    totalPositionSize.abs(),
                    _quoteAssetReserve,
                    _baseAssetReserve
                )
            )
                .mulScalar(-1);
        }

        return cumulativeNotional.subD(mmCumulativeNotional).addD(detalCloseAmount);
    }

    function adjustTotalPosition(
        SignedDecimal.signedDecimal memory adjustedPosition,
        SignedDecimal.signedDecimal memory oldAdjustedPosition
    ) public override onlyCounterParty {
        totalPositionSize = totalPositionSize.addD(adjustedPosition).subD(oldAdjustedPosition);
    }
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxHoldingBaseAsset","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"openInterestNotionalCap","type":"uint256"}],"name":"CapChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"rate","type":"int256"},{"indexed":false,"internalType":"uint256","name":"underlyingPrice","type":"uint256"}],"name":"FundingRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"quoteReserve","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseReserve","type":"uint256"},{"indexed":false,"internalType":"int256","name":"cumulativeNotional","type":"int256"}],"name":"LiquidityChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"ammPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oraclePrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adjustPrice","type":"uint256"},{"indexed":false,"internalType":"int256","name":"MMLiquidity","type":"int256"},{"indexed":false,"internalType":"int256","name":"MMPNL","type":"int256"},{"indexed":false,"internalType":"bool","name":"moved","type":"bool"}],"name":"MoveAMMPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"quoteAssetReserve","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseAssetReserve","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ReserveSnapshotted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"settlementPrice","type":"uint256"}],"name":"Shutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IExchangeTypes.Dir","name":"dir","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"quoteAssetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseAssetAmount","type":"uint256"}],"name":"SwapInput","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IExchangeTypes.Dir","name":"dir","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"quoteAssetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseAssetAmount","type":"uint256"}],"name":"SwapOutput","type":"event"},{"inputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"adjustedPosition","type":"tuple"},{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"oldAdjustedPosition","type":"tuple"}],"name":"adjustTotalPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseAssetReserve","outputs":[{"internalType":"uint256","name":"d","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum ISakePerpVaultTypes.Risk","name":"_risk","type":"uint8"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"_baseAssetAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_fromQuoteReserve","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_fromBaseReserve","type":"tuple"}],"name":"calcBaseAssetAfterLiquidityMigration","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetAmount","type":"tuple"}],"name":"calcFee","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeState","outputs":[{"internalType":"contract IExchangeState","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fluctuationLimitRatio","outputs":[{"internalType":"uint256","name":"d","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundingBufferPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundingRate","outputs":[{"internalType":"int256","name":"d","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCumulativeNotional","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IExchangeTypes.Dir","name":"_dir","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetAmount","type":"tuple"}],"name":"getInputPrice","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IExchangeTypes.Dir","name":"_dir","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetPoolAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetPoolAmount","type":"tuple"}],"name":"getInputPriceWithReserves","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IExchangeTypes.Dir","name":"_dir","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetAmount","type":"tuple"}],"name":"getInputTwap","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestLiquidityChangedSnapshots","outputs":[{"components":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"cumulativeNotional","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"quoteAssetReserve","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"baseAssetReserve","type":"tuple"},{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"totalPositionSize","type":"tuple"}],"internalType":"struct IExchangeTypes.LiquidityChangedSnapshot","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"name":"getLiquidityChangedSnapshots","outputs":[{"components":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"cumulativeNotional","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"quoteAssetReserve","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"baseAssetReserve","type":"tuple"},{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"totalPositionSize","type":"tuple"}],"internalType":"struct IExchangeTypes.LiquidityChangedSnapshot","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLiquidityHistoryLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetReserve","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetReserve","type":"tuple"}],"name":"getMMUnrealizedPNL","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxHoldingBaseAsset","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOpenInterestNotionalCap","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IExchangeTypes.Dir","name":"_dir","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetAmount","type":"tuple"}],"name":"getOutputPrice","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IExchangeTypes.Dir","name":"_dir","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetPoolAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetPoolAmount","type":"tuple"}],"name":"getOutputPriceWithReserves","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IExchangeTypes.Dir","name":"_dir","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetAmount","type":"tuple"}],"name":"getOutputTwap","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserve","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSettlementPrice","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSnapshotLen","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSpotPrice","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalPositionSize","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_intervalInSeconds","type":"uint256"}],"name":"getTwapPrice","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingPrice","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_intervalInSeconds","type":"uint256"}],"name":"getUnderlyingTwapPrice","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initMarginRatio","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_quoteAssetReserve","type":"uint256"},{"internalType":"uint256","name":"_baseAssetReserve","type":"uint256"},{"internalType":"uint256","name":"_tradeLimitRatio","type":"uint256"},{"internalType":"uint256","name":"_fundingPeriod","type":"uint256"},{"internalType":"contract IPriceFeed","name":"_priceFeed","type":"address"},{"internalType":"contract ISakePerp","name":"_sakePerp","type":"address"},{"internalType":"contract ISakePerpVault","name":"_sakePerpVault","type":"address"},{"internalType":"bytes32","name":"_priceFeedKey","type":"bytes32"},{"internalType":"address","name":"_quoteAsset","type":"address"},{"internalType":"uint256","name":"_fluctuationLimitRatio","type":"uint256"},{"internalType":"uint256","name":"_priceAdjustRatio","type":"uint256"},{"internalType":"contract IExchangeState","name":"_exchangeState","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isOverSpreadLimit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastMoveAmmPriceTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationFeeRatio","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maintenanceMarginRatio","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLiquidationFee","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_liquidityMultiplier","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_fluctuationLimitRatio","type":"tuple"}],"name":"migrateLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ISakePerpVaultTypes.Risk","name":"_risk","type":"uint8"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_oraclePrice","type":"uint256"},{"internalType":"bytes32","name":"_priceFeedKey","type":"bytes32"}],"name":"moveAMMPriceToOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mover","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextFundingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"open","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oraclePriceSpreadLimit","outputs":[{"internalType":"uint256","name":"d","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceAdjustRatio","outputs":[{"internalType":"uint256","name":"d","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteAsset","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteAssetReserve","outputs":[{"internalType":"uint256","name":"d","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"reserveSnapshots","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"quoteAssetReserve","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"baseAssetReserve","type":"tuple"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sakePerp","outputs":[{"internalType":"contract ISakePerp","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sakePerpVault","outputs":[{"internalType":"contract ISakePerpVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_counterParty","type":"address"}],"name":"setCounterParty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_exchangeState","type":"address"}],"name":"setExchangeState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_fluctuationLimitRatio","type":"tuple"}],"name":"setFluctuationLimitRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"setMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newMover","type":"address"}],"name":"setMover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_open","type":"bool"}],"name":"setOpen","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_limit","type":"tuple"}],"name":"setOraclePriceSpreadLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_priceAdjustRatio","type":"tuple"}],"name":"setPriceAdjustRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeed","type":"address"}],"name":"setPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_interval","type":"uint256"}],"name":"setSpotPriceTwapInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleFunding","outputs":[{"components":[{"internalType":"int256","name":"d","type":"int256"}],"internalType":"struct SignedDecimal.signedDecimal","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"spotPriceTwapInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spreadRatio","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IExchangeTypes.Dir","name":"_dir","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetAmountLimit","type":"tuple"}],"name":"swapInput","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IExchangeTypes.Dir","name":"_dir","type":"uint8"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_baseAssetAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"_quoteAssetAmountLimit","type":"tuple"},{"internalType":"bool","name":"_skipFluctuationCheck","type":"bool"}],"name":"swapOutput","outputs":[{"components":[{"internalType":"uint256","name":"d","type":"uint256"}],"internalType":"struct Decimal.decimal","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalPositionSize","outputs":[{"internalType":"int256","name":"d","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradeLimitRatio","outputs":[{"internalType":"uint256","name":"d","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50615296806100206000396000f3fe608060405234801561001057600080fd5b506004361061043e5760003560e01c806383acb48a11610236578063dc3184a01161013b578063eebab8ef116100c3578063fc0e74d111610087578063fc0e74d11461082a578063fca3b5aa14610832578063fcfff16f14610845578063fdf262b71461084d578063ffbf688e146108555761043e565b8063eebab8ef146107d6578063eebd72e0146107e9578063f1b5df86146107fc578063f1e286501461080f578063f2fde38b146108175761043e565b8063e4bc2eb91161010a578063e4bc2eb9146107ae578063e57d5636146107b6578063ec2c0e63146107be578063ed83d79c146107c6578063eeb016f2146107ce5761043e565b8063dc3184a014610778578063dc76fabc1461078b578063e0037a6c14610793578063e1f1027f1461079b5761043e565b8063a8f8be4e116101be578063c2de442f1161018d578063c2de442f1461073a578063c9566fcc14610742578063cfe711031461074a578063d835e52314610752578063da0c5927146107655761043e565b8063a8f8be4e146106f9578063ae09a4571461070c578063ba0c476314610714578063bea69f74146107275761043e565b80638f40d932116102055780638f40d932146106a35780639bf5d1d4146106ab5780639e010362146106be5780639ece77c8146106d35780639ffca62f146106e65761043e565b806383acb48a146106785780638da5cb5b146106805780638e483328146106885780638eb86e8b146106905761043e565b80634cb876f21161034757806362e7a176116102cf5780637155c361116102935780637155c3611461062f578063724e78da14610642578063741bef1a1461065557806374d7c62b1461065d57806377481024146106655761043e565b806362e7a176146105e65780636fa42ede146105f95780636fdca5e01461060c5780636febdd501461061f578063715018a6146106275761043e565b80635834db90116103165780635834db901461059a57806358a4c3dc146105ad57806359bf5d39146105b55780635f1ba1fd146105cb57806362267955146105d35761043e565b80634cb876f21461056f57806350799c8114610577578063517587c61461058a57806352545410146105925761043e565b806329f9b17b116103ca57806341d3c84c1161039957806341d3c84c1461053c578063429f24bc1461054457806342b3198b1461054c578063468f02d2146105545780634894d1831461055c5761043e565b806329f9b17b146104f9578063349532491461050157806340098b751461051457806340d71cd9146105295761043e565b80631b584d6c116104115780631b584d6c146104935780631d3acb44146104a857806320855f05146104b057806321e00985146104c3578063237f17ee146104e65761043e565b80630d451c8f146104435780630dd27120146104615780630f999b1514610476578063113773941461047e575b600080fd5b61044b61085d565b604051610458919061496b565b60405180910390f35b610469610863565b6040516104589190614909565b61044b610872565b610486610878565b6040516104589190615165565b61049b61090b565b604051610458919061512c565b61044b610993565b6104866104be3660046147aa565b610999565b6104d66104d1366004614802565b610a78565b604051610458949392919061517f565b61049b6104f4366004614802565b610ac6565b610486610b6f565b61048661050f366004614802565b610b8b565b610527610522366004614578565b610c2a565b005b6104866105373660046147c6565b610ca7565b61044b610d58565b61044b610d5e565b61044b610d64565b610486610d6a565b61048661056a366004614657565b610e07565b61044b610e1e565b61048661058536600461468c565b610e24565b610469610ebd565b610486610ecc565b6105276105a836600461473f565b610f22565b61044b6111f6565b6105bd6111fc565b60405161045892919061516f565b61044b61122e565b6104866105e1366004614724565b611234565b6105276105f4366004614802565b6112bc565b610486610607366004614657565b611313565b61052761061a366004614594565b61132a565b6104866113d2565b610527611428565b61052761063d366004614578565b6114a7565b610527610650366004614578565b611524565b6104696115a1565b61044b6115b0565b61052761067336600461476a565b6115b6565b610486611626565b61046961167c565b61046961168b565b61052761069e3660046146e4565b61169a565b61044b61173a565b6104866106b936600461468c565b611740565b6106c661177e565b6040516104589190614960565b6105276106e1366004614578565b6118a5565b6104866106f43660046145b4565b6118fc565b61052761070736600461476a565b611b2b565b610469611b66565b6105276107223660046147aa565b611b75565b610527610735366004614853565b611bd8565b61044b6120c4565b61044b6120ca565b6104866120d0565b61052761076036600461476a565b612126565b610486610773366004614657565b612161565b6104866107863660046145fa565b612193565b610486612221565b61044b612250565b6104866107a9366004614657565b612256565b61044b612288565b61048661228e565b6104866122e4565b610486612300565b610486612476565b6105276107e43660046146e4565b6124cc565b6105276107f7366004614832565b61255e565b61048661080a366004614802565b612aa4565b61044b612ab5565b610527610825366004614578565b612abb565b610527612b72565b610527610840366004614578565b612d46565b6106c6612d9d565b610469612dad565b610486612dbc565b60a75490565b60af546001600160a01b031681565b60ad5481565b610880614470565b60af60009054906101000a90046001600160a01b03166001600160a01b031663113773946040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ce57600080fd5b505afa1580156108e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109069190614785565b905090565b610913614483565b60a18054610922906001612dd8565b8154811061092c57fe5b60009182526020918290206040805160a0810182526004909302909101805460808401908152835281518085018352600182015481528385015281518085018352600282015481528383015281519384019091526003015482526060810191909152905090565b609f5481565b6109a1614470565b6109a9614470565b604080516020810190915260975481526109c290612e1a565b156109fe57604080516020810190915260975481526109f7906109f2906001906109eb90612e38565b8688611740565b612e66565b9050610a3b565b610a38600019610a326109f26000610a2b6097604051806020016040529081600082015481525050612e38565b888a611740565b90612eca565b90505b6040805160208082018352609a54825282519081019092526099548252610a6e918391610a689190612eef565b90612f0c565b9150505b92915050565b60a78181548110610a8557fe5b600091825260209182902060408051808501825260049093029091018054835281519384019091526001810154835260028101546003909101549193509084565b610ace614483565b60a1548210610af85760405162461bcd60e51b8152600401610aef90614c5e565b60405180910390fd5b60a18281548110610b0557fe5b60009182526020918290206040805160a081018252600490930290910180546080840190815283528151808501835260018201548152838501528151808501835260028201548152838301528151938401909152600301548252606081019190915290505b919050565b610b77614470565b506040805160208101909152609954815290565b610b93614470565b60408051602081019182905260aa5460a654632885cf7d60e21b909352909182916001600160a01b03169063a2173df490610bd2908760248601614974565b60206040518083038186803b158015610bea57600080fd5b505afa158015610bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c22919061481a565b905292915050565b610c32612f29565b6033546001600160a01b03908116911614610c5f5760405162461bcd60e51b8152600401610aef90614eb9565b6001600160a01b038116610c855760405162461bcd60e51b8152600401610aef90614cb6565b60ae80546001600160a01b0319166001600160a01b0392909216919091179055565b610caf614470565b610cb884612f2d565b610cc3575082610d51565b600080610ccf86612f3f565b13610cdb576000610cde565b60015b9050610ce8614470565b610d0a82610cf7576001610cfa565b60005b610d0388612e38565b8787611740565b9050610d14614470565b610d2f6109f284610d26576000610d29565b60015b84612256565b9050610d4b83610d4157600019610d44565b60015b8290612eca565b93505050505b9392505050565b60985481565b60ac5481565b60a15490565b610d72614470565b60408051602081019182905260aa5460a6546331d98b3f60e01b909352909182916001600160a01b0316906331d98b3f90610db0906024850161496b565b60206040518083038186803b158015610dc857600080fd5b505afa158015610ddc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e00919061481a565b9052905090565b610e0f614470565b610d5183836000610384612f43565b60975481565b610e2c614470565b60af546040516350799c8160e01b81526001600160a01b03909116906350799c8190610e62908890889088908890600401614982565b60206040518083038186803b158015610e7a57600080fd5b505afa158015610e8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb29190614785565b90505b949350505050565b60a8546001600160a01b031681565b610ed4614470565b60af60009054906101000a90046001600160a01b03166001600160a01b031663525454106040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ce57600080fd5b610f2a612f29565b6033546001600160a01b03908116911614610f575760405162461bcd60e51b8152600401610aef90614eb9565b610f67610f62612fc9565b612f3f565b610f79610f623685900385018561476a565b1415610f975760405162461bcd60e51b8152600401610aef90614a48565b60408051602081019091526097548152610fbf90610fba3685900385018561476a565b612fe6565b610fd6610fd13683900383018361476a565b613066565b610fde614470565b506040805160208101909152609d548152610ff7614470565b506040805160208101909152609e548152611010614470565b506040805160208101909152609754815261103a6110333687900387018761476a565b84906131b6565b51609d556110576110503687900387018761476a565b83906131b6565b51609e55611066818484610ca7565b5160978190556040805160a081018252609954608082019081528152815160208082018452609d8054835281840192835284518083018652609e548152848601908152855180840187529687526060850196875260a180546001810182556000919091529451517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f6498786004909602958601559251517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f6498798501559151517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987a8401559351517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987b9092019190915581519283019091525481527feba648fc83514e32ba75e27696ee5fa3610ebc7a77460a3ac3e8724ffa1be4cc906111a690612f3f565b6040805160208101909152609e5481526111bf90612f3f565b604080516020810190915260995481526111d890612f3f565b6040516111e79392919061519a565b60405180910390a15050505050565b60a65481565b611204614470565b61120c614470565b50506040805160208082018352609d5482528251908101909252609e54825291565b60a25481565b61123c614470565b60af54604051636226795560e01b81526001600160a01b039091169063622679559061126c90859060040161515b565b60206040518083038186803b15801561128457600080fd5b505afa158015611298573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a729190614785565b6112c4612f29565b6033546001600160a01b039081169116146112f15760405162461bcd60e51b8152600401610aef90614eb9565b8061130e5760405162461bcd60e51b8152600401610aef90614b4c565b60a255565b61131b614470565b610d5183836001610384612f43565b611332612f29565b6033546001600160a01b0390811691161461135f5760405162461bcd60e51b8152600401610aef90614eb9565b60ab5460ff600160a01b909104161515811515141561137d576113cf565b60ab805482158015600160a01b0260ff60a01b19909216919091179091556113cf576113cb610e106113c5610e106113bf60a3546113b96131d3565b906131d7565b906131fc565b9061323e565b60a5555b50565b6113da614470565b60af60009054906101000a90046001600160a01b03166001600160a01b0316636febdd506040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ce57600080fd5b611430612f29565b6033546001600160a01b0390811691161461145d5760405162461bcd60e51b8152600401610aef90614eb9565b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380546001600160a01b0319169055565b6114af612f29565b6033546001600160a01b039081169116146114dc5760405162461bcd60e51b8152600401610aef90614eb9565b6001600160a01b0381166115025760405162461bcd60e51b8152600401610aef90614cb6565b60af80546001600160a01b0319166001600160a01b0392909216919091179055565b61152c612f29565b6033546001600160a01b039081169116146115595760405162461bcd60e51b8152600401610aef90614eb9565b6001600160a01b03811661157f5760405162461bcd60e51b8152600401610aef90614cb6565b60aa80546001600160a01b0319166001600160a01b0392909216919091179055565b60aa546001600160a01b031681565b60a35481565b6115be612f29565b6033546001600160a01b039081169116146115eb5760405162461bcd60e51b8152600401610aef90614eb9565b60006115ff6115f8612fc9565b8390613278565b60000b13156116205760405162461bcd60e51b8152600401610aef90614f35565b5160a055565b61162e614470565b60af60009054906101000a90046001600160a01b03166001600160a01b03166383acb48a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ce57600080fd5b6033546001600160a01b031690565b60ab546001600160a01b031681565b6116a2612f29565b60a8546001600160a01b039081169116146116cf5760405162461bcd60e51b8152600401610aef90614ddc565b60af54604051638eb86e8b60e01b81526001600160a01b0390911690638eb86e8b90611703908690869086906004016149cb565b600060405180830381600087803b15801561171d57600080fd5b505af1158015611731573d6000803e3d6000fd5b50505050505050565b609c5481565b611748614470565b60af546040516326fd747560e21b81526001600160a01b0390911690639bf5d1d490610e62908890889088908890600401614982565b6000611788614470565b611790610d6a565b9050600061179d82612f3f565b116117ba5760405162461bcd60e51b8152600401610aef90614c87565b6117c2614470565b6117ca612221565b90506117d4614470565b6117f96117f4846117ee866117e887612e66565b906132a9565b90613318565b612e38565b905061188460af60009054906101000a90046001600160a01b03166001600160a01b03166337292b606040518163ffffffff1660e01b815260040160206040518083038186803b15801561184c57600080fd5b505afa158015611860573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f629190614785565b61188d82612f3f565b101561189a57600061189d565b60015b935050505090565b6118ad612f29565b6033546001600160a01b039081169116146118da5760405162461bcd60e51b8152600401610aef90614eb9565b60ab80546001600160a01b0319166001600160a01b0392909216919091179055565b611904614470565b60ab54600160a01b900460ff1661192d5760405162461bcd60e51b8152600401610aef90614f5c565b611935612f29565b60ab546001600160a01b039081169116146119625760405162461bcd60e51b8152600401610aef90614b83565b611974610f623685900385018561476a565b6119875761198061338c565b9050610d51565b600184600181111561199557fe5b14156119f5576119ad610f623685900385018561476a565b6040805160208082018352609c5482528251908101909252609d5482526119d791610f62916131b6565b10156119f55760405162461bcd60e51b8152600401610aef90614bfb565b6119fd614470565b611a10856107a93687900387018761476a565b9050611a24610f623685900385018561476a565b15611ab4576000856001811115611a3757fe5b1415611a7b57611a4f610f623685900385018561476a565b611a5882612f3f565b1015611a765760405162461bcd60e51b8152600401610aef90614e82565b611ab4565b611a8d610f623685900385018561476a565b611a9682612f3f565b1115611ab45760405162461bcd60e51b8152600401610aef90614fc0565b611acf85611ac73687900387018761476a565b8360006133a7565b7fae6a2b946841d9afc0e1e19a94ae4af26f01125b87b5095bbfb177a9741a2ede85611b03610f623688900388018861476a565b611b0c84612f3f565b604051611b1b939291906149aa565b60405180910390a1949350505050565b611b33612f29565b6033546001600160a01b03908116911614611b605760405162461bcd60e51b8152600401610aef90614eb9565b51609f55565b60ae546001600160a01b031681565b611b7d612f29565b60ab546001600160a01b03908116911614611baa5760405162461bcd60e51b8152600401610aef90614b83565b60408051602081019091526097548152611bd0908290611bca9085612f0c565b90612eef565b516097555050565b600054610100900460ff1680611bf15750611bf16134dd565b80611bff575060005460ff16155b611c1b5760405162461bcd60e51b8152600401610aef90614d4d565b600054610100900460ff16158015611c46576000805460ff1961ff0019909116610100171660011790555b8c15801590611c5457508a15155b8015611c5f57508b15155b8015611c6a57508915155b8015611c7e57506001600160a01b03891615155b8015611c9257506001600160a01b03881615155b8015611ca657506001600160a01b03871615155b8015611cba57506001600160a01b03821615155b8015611cce57506001600160a01b03851615155b611cea5760405162461bcd60e51b8152600401610aef9061505e565b611cf26134e3565b6040805160208082018352908f9052609d8f9055815180820183528e9052609e8e9055815180820183528d9052609c8d90558151808201835285905260a08590558151908101909152849052609f84905560a38a9055611d538a60026131fc565b60a455610e1060a25560a686905560a980546001600160a01b03199081166001600160a01b038881169190911790925560aa805482168c841617905560ab805482168b841617905560a8805482168a841617905560af80549091169184169190911790556040805160208101909152670429d069189e00009081905260ad55611dda612f29565b60ae80546001600160a01b0319166001600160a01b0392831617905560a85460405163025c4d3560e51b8152911690634b89a6a090611e2190309061019090600401614947565b600060405180830381600087803b158015611e3b57600080fd5b505af1158015611e4f573d6000803e3d6000fd5b505060a8546040516386be9e8b60e01b81526001600160a01b0390911692506386be9e8b9150611e8990309060009060329060040161491d565b600060405180830381600087803b158015611ea357600080fd5b505af1158015611eb7573d6000803e3d6000fd5b505060a8546040516386be9e8b60e01b81526001600160a01b0390911692506386be9e8b9150611ef190309060019060199060040161491d565b600060405180830381600087803b158015611f0b57600080fd5b505af1158015611f1f573d6000803e3d6000fd5b5050505060a16040518060800160405280611f3861338c565b81526040805160208181018352609d5482528084019190915281519081018252609e54815290820152606001611f6c61338c565b9052815460018181018455600093845260209384902083515160049093020191825583830151519082015560408083015151600283015560609092015151600390910155805160a081018252609d5460808201908152815281518084018352609e5481529281019290925260a791908101611fe56131d3565b8152602001611ff2613575565b90528154600181810184556000938452602093849020835151600490930201918255838301515190820155604080830151600283015560609092015160039091015580519182019052609d5481527f3a3348362552c3897fd1f06a3233519ebd8bd76ad6e99a418a9741155fe905159061206b90612f3f565b6040805160208101909152609e54815261208490612f3f565b61208c6131d3565b60405161209b9392919061519a565b60405180910390a180156120b5576000805461ff00191690555b50505050505050505050505050565b60a45481565b609e5481565b6120d8614470565b60af60009054906101000a90046001600160a01b03166001600160a01b031663cfe711036040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ce57600080fd5b61212e612f29565b6033546001600160a01b0390811691161461215b5760405162461bcd60e51b8152600401610aef90614eb9565b5160ad55565b612169614470565b6040805160208082018352609d5482528251908101909252609e548252610d519185918591611740565b61219b614470565b60ab54600160a01b900460ff166121c45760405162461bcd60e51b8152600401610aef90614f5c565b6121cc612f29565b60ab546001600160a01b039081169116146121f95760405162461bcd60e51b8152600401610aef90614b83565b610eb28561220c3687900387018761476a565b61221b3687900387018761476a565b85613579565b612229614470565b6040805160208082018352609e5482528251908101909252609d548252610906919061372c565b60a55481565b61225e614470565b6040805160208082018352609d5482528251908101909252609e548252610d519185918591610e24565b609d5481565b612296614470565b60af60009054906101000a90046001600160a01b03166001600160a01b031663e57d56366040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ce57600080fd5b6122ec614470565b506040805160208101909152609b54815290565b612308614470565b60ab54600160a01b900460ff166123315760405162461bcd60e51b8152600401610aef90614f5c565b612339612f29565b60ab546001600160a01b039081169116146123665760405162461bcd60e51b8152600401610aef90614b83565b60a5546123716131d3565b101561238f5760405162461bcd60e51b8152600401610aef90614ff7565b612397614470565b61239f61338c565b90506123a9614470565b6123b460a254610b8b565b905060a5546123d060a35460ac546131d790919063ffffffff16565b1015612418576123de614470565b6123f0826117e86109f260a254612aa4565b90506124146201518061240e60a3548461374990919063ffffffff16565b906137a6565b9250505b61242282826137c2565b600061243260a4546113b96131d3565b90506000612459610e106113c5610e106113bf60a35460a5546131d790919063ffffffff16565b9050818111612468578161246a565b805b60a55550919250505090565b61247e614470565b60af60009054906101000a90046001600160a01b03166001600160a01b031663eeb016f26040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ce57600080fd5b60ab54600160a01b900460ff166124f55760405162461bcd60e51b8152600401610aef90614f5c565b6124fd612f29565b60a8546001600160a01b0390811691161461252a5760405162461bcd60e51b8152600401610aef90614ddc565b60af5460405163eebab8ef60e01b81526001600160a01b039091169063eebab8ef90611703908690869086906004016149cb565b612566612f29565b60ae546001600160a01b03908116911614806125975750612585612f29565b60aa546001600160a01b039081169116145b6125b35760405162461bcd60e51b8152600401610aef90614a77565b600082116125d35760405162461bcd60e51b8152600401610aef90614cdf565b8060a654146125f45760405162461bcd60e51b8152600401610aef9061502e565b60ab54600160a01b900460ff1615806126235750604080516020810190915260a054815261262190612f3f565b155b1561262d57612aa0565b612635614470565b50604080516020810190915282815261264c614470565b6040805160208082018352609e5482528251908101909252609d548252612673919061372c565b604080516020810190915260ad5481529091506000906126ad9061269790846131b6565b6126a76117f4856117e888612e66565b90613278565b60000b13156126ce5760405162461bcd60e51b8152600401610aef906150c9565b6126d6614470565b604080516020810190915260a054815261270e906117f490612705906126ff866117e889612e66565b9061382e565b610a6885612e66565b9050612718614470565b6040805160208082018352609e5482528251908101909252609d54825261273f91906131b6565b9050600061275e612751610f62612fc9565b6113c5610f62858761372c565b9050612768614470565b604051806020016040528061277c84613899565b90529050612788614470565b612792848361372c565b905061279c614470565b6127a68383610999565b90506127b0614470565b60a85460405163180c91f160e01b81526001600160a01b039091169063180c91f1906127e0903090600401614909565b60206040518083038186803b1580156127f857600080fd5b505afa15801561280c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128309190614785565b905061283a614470565b60a85460405163633ceadb60e01b81526001600160a01b039091169063633ceadb9061286a903090600401614909565b60206040518083038186803b15801561288257600080fd5b505afa158015612896573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ba9190614785565b90506128d86128d3826128cd8686612f0c565b906138f3565b612e1a565b15612944577f2ad23a1b94bd43bf2d22d82564f2f357d4428e8146810a57fbaef7b88ddc6fba6129078a612f3f565b8d6129118b612f3f565b61291a86612f3f565b61292388612f3f565b6000604051612937969594939291906151b0565b60405180910390a1612a95565b61294c614470565b6040805160208101909152609d548152612969906117e887612e66565b6040805160208101909152609a5481529091506129869082612f0c565b51609a55604080516020810190915260995481526129a49082612f0c565b516099558551609e558451609d556129ba6131d3565b60ac556129c5613958565b60a860009054906101000a90046001600160a01b03166001600160a01b0316638df3fab36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a1557600080fd5b505af1158015612a29573d6000803e3d6000fd5b505050507f2ad23a1b94bd43bf2d22d82564f2f357d4428e8146810a57fbaef7b88ddc6fba612a578b612f3f565b8e612a618c612f3f565b612a6e610f6288886138f3565b612a7789612f3f565b6001604051612a8b969594939291906151b0565b60405180910390a1505b505050505050505050505b5050565b612aac614470565b610a7282613a90565b60a05481565b612ac3612f29565b6033546001600160a01b03908116911614612af05760405162461bcd60e51b8152600401610aef90614eb9565b6001600160a01b038116612b165760405162461bcd60e51b8152600401610aef90614acf565b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b612b7a612f29565b6033546001600160a01b03908116911614612ba75760405162461bcd60e51b8152600401610aef90614eb9565b60a860009054906101000a90046001600160a01b03166001600160a01b0316638df3fab36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612bf757600080fd5b505af1158015612c0b573d6000803e3d6000fd5b50505050612c17614483565b612c1f61090b565b9050612c29614470565b60208201516040830151612c3c916131b6565b9050612c46614470565b60408301516060840151612c59916138f3565b9050612c63614470565b612c7682612c7085612e66565b90613ac1565b9050612c80614470565b6040805160208101909152609d548152612c9b9083906132a9565b60408051602081019091526097548152909150606490612cba90612f2d565b1115612cf15760408051602081019091526097548152612cec90612cdd90612e38565b612ce683612e38565b9061372c565b51609b555b60ab805460ff60a01b191690556040805160208101909152609b5481527f574214b195bf5273a95bb4498e35cf1fde0ce327c727a95ec2ab359f7ba4e11a90612d3990612f3f565b6040516111e7919061496b565b612d4e612f29565b6033546001600160a01b03908116911614612d7b5760405162461bcd60e51b8152600401610aef90614eb9565b60a880546001600160a01b0319166001600160a01b0392909216919091179055565b60ab54600160a01b900460ff1681565b60a9546001600160a01b031681565b612dc4614470565b506040805160208101909152609754815290565b6000610d5183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613ade565b60008082600001511215612e3057506001610b6a565b506000919050565b612e40614470565b612e48614470565b825160001315612e5e5782516000038152610a72565b915182525090565b612e6e614470565b8180600001516001600160ff1b03101560405180606001604052806033815260200161522e6033913990612eb55760405162461bcd60e51b8152600401610aef91906149f5565b50506040805160208101909152915182525090565b612ed2614470565b612eda614470565b8351612ee69084613b0a565b81529392505050565b612ef7614470565b612eff614470565b82518451612ee691613b75565b612f14614470565b612f1c614470565b82518451612ee691613bbb565b3390565b6000612f3882612e38565b5192915050565b5190565b612f4b614470565b612f536144c2565b600180825260a754612f6491612dd8565b60208201526040810151866001811115612f7a57fe5b90816001811115612f8757fe5b905250604080820180516020018790525101846001811115612fa557fe5b90816001811115612fb257fe5b905250612fbf8184613c01565b9695505050505050565b612fd1614470565b6040518060200160405280610e006012613e2c565b6000612ff183612f3f565b1315612aa057612fff614470565b6040805160208082018352609e5482528251908101909252633b9aca008252613032916117f491906117ee9087906138f3565b905060006130408383613278565b60000b12156130615760405162461bcd60e51b8152600401610aef90614c27565b505050565b600061307182612f3f565b11156113cf5760a7546130826144e1565b60a7600183038154811061309257fe5b60009182526020918290206040805160a08101825260049093029091018054608084019081528352815180850183526001820154815293830193909352600283015490820152600390910154606082015290506130ed613575565b81606001511480156130ff5750600182115b156131685760a7600283038154811061311457fe5b60009182526020918290206040805160a08101825260049093029091018054608084019081528352815180850183526001820154815293830193909352600283015490820152600390910154606082015290505b6040805160208082018352609e5482528251908101909252609d548252613199916131929161372c565b8483613e35565b156130615760405162461bcd60e51b8152600401610aef90614d16565b6131be614470565b6131c6614470565b82518451612ee691613ed7565b4290565b600082820183811015610d515760405162461bcd60e51b8152600401610aef90614b15565b6000610d5183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ee5565b60008261324d57506000610a72565b8282028284828161325a57fe5b0414610d515760405162461bcd60e51b8152600401610aef90614e41565b80518251600091101561328d57506001610a72565b8151835110156132a05750600019610a72565b50600092915050565b6132b1614470565b8180600001516001600160ff1b03101560405180606001604052806033815260200161522e60339139906132f85760405162461bcd60e51b8152600401610aef91906149f5565b50613301614470565b8351855161330e91613b75565b8152949350505050565b613320614470565b8180600001516001600160ff1b03101560405180606001604052806033815260200161522e60339139906133675760405162461bcd60e51b8152600401610aef91906149f5565b50613370614470565b61338361337c85612e66565b8690613ac1565b95945050505050565b613394614470565b5060408051602081019091526000815290565b60008460018111156133b557fe5b1415613438576040805160208101909152609d5481526133d59084613f1c565b51609d556040805160208101909152609e5481526133f39083613f39565b51609e556040805160208101909152609754815261341190836138f3565b516097556040805160208101909152609954815261342f90846138f3565b516099556134b1565b6040805160208101909152609d5481526134529084613f39565b51609d556040805160208101909152609e5481526134709083613f1c565b51609e556040805160208101909152609754815261348e90836132a9565b51609755604080516020810190915260995481526134ac90846132a9565b516099555b806134cf576040805160208101909152609f5481526134cf90613066565b6134d7613958565b50505050565b303b1590565b600054610100900460ff16806134fc57506134fc6134dd565b8061350a575060005460ff16155b6135265760405162461bcd60e51b8152600401610aef90614d4d565b600054610100900460ff16158015613551576000805460ff1961ff0019909116610100171660011790555b613559613f56565b613561613fd7565b80156113cf576000805461ff001916905550565b4390565b613581614470565b61358a84612f3f565b61359d5761359661338c565b9050610eb5565b60018560018111156135ab57fe5b1415613602576135ba84612f3f565b6040805160208082018352609c5482528251908101909252609e5482526135e491610f62916131b6565b10156136025760405162461bcd60e51b8152600401610aef90614bfb565b61360a614470565b6136148686612161565b905061361f84612f3f565b1561369d57600086600181111561363257fe5b141561366d5761364184612f3f565b61364a82612f3f565b10156136685760405162461bcd60e51b8152600401610aef90614e0a565b61369d565b61367684612f3f565b61367f82612f3f565b111561369d5760405162461bcd60e51b8152600401610aef90614f89565b826136b0576136ad8682876140b1565b92505b6136d860008760018111156136c157fe5b146136cd5760006136d0565b60015b8287866133a7565b7f0dd4066b1a6ce97fb670c3e4201e908c644193f38cbdaffd0229d7e26da3e5338661370383612f3f565b61370c88612f3f565b60405161371b939291906149aa565b60405180910390a195945050505050565b613734614470565b61373c614470565b82518451612ee6916141cd565b613751614470565b816001600160ff1b03101560405180606001604052806033815260200161522e60339139906137935760405162461bcd60e51b8152600401610aef91906149f5565b5061379c614470565b610a6e8484612eca565b6137ae614470565b6137b6614470565b8351612ee690846141db565b6137cc8282613318565b51609881905560408051602081019091529081527fd2805fe76d30598332a67c1061cee82e2e102b0f59f5457b1729bce028a054a09061380b90612f3f565b61381483612f3f565b604051613822929190614974565b60405180910390a15050565b613836614470565b8180600001516001600160ff1b03101560405180606001604052806033815260200161522e603391399061387d5760405162461bcd60e51b8152600401610aef91906149f5565b50613886614470565b61338361389285612e66565b869061423f565b600060038211156138dd5781600160028204015b818110156138d5578091506002818286816138c457fe5b0401816138cd57fe5b0490506138ad565b509050610b6a565b81156138eb57506001610b6a565b506000610b6a565b6138fb614470565b8180600001516001600160ff1b03101560405180606001604052806033815260200161522e60339139906139425760405162461bcd60e51b8152600401610aef91906149f5565b5061394b614470565b8351855161330e91613bbb565b6000613962613575565b60a78054919250600091600019810190811061397a57fe5b9060005260206000209060040201905080600301548214156139a857609d548155609e546001820155613a25565b6040805160a081018252609d54608082019081528152815160208181018452609e54825282015260a79181016139dc6131d3565b8152602090810185905282546001818101855560009485529382902083515160049092020190815590820151519281019290925560408101516002830155606001516003909101555b6040805160208101909152609d5481527f3a3348362552c3897fd1f06a3233519ebd8bd76ad6e99a418a9741155fe9051590613a6090612f3f565b6040805160208101909152609e548152613a7990612f3f565b613a816131d3565b6040516138229392919061519a565b613a98614470565b613aa06144c2565b6000815260a754613ab2906001612dd8565b6020820152610d518184613c01565b613ac9614470565b613ad1614470565b82518451612ee69161425c565b60008184841115613b025760405162461bcd60e51b8152600401610aef91906149f5565b505050900390565b600082613b1957506000610a72565b82600019148015613b2d5750600160ff1b82145b15613b4a5760405162461bcd60e51b8152600401610aef90614eee565b82820282848281613b5757fe5b0514610d515760405162461bcd60e51b8152600401610aef90614eee565b6000818303818312801590613b8a5750838113155b80613b9f5750600083128015613b9f57508381135b610d515760405162461bcd60e51b8152600401610aef90615085565b6000828201818312801590613bd05750838112155b80613be55750600083128015613be557508381125b610d515760405162461bcd60e51b8152600401610aef90614bba565b613c09614470565b613c11614470565b613c1a8461426a565b905082613c28579050610a72565b6000613c3c84613c366131d3565b90612dd8565b9050613c466144e1565b60a7866020015181548110613c5757fe5b60009182526020918290206040805160a081018252600490930290910180546080840190815283528151808501835260018083015482529484015260028101549183019190915260030154606082015260a7549092501480613cbd575081816040015111155b15613ccd57829350505050610a72565b60408101516000613ce082613c366131d3565b9050613cea614470565b613cf486836143c2565b90505b6020890151613d1757613d0a81836143de565b9650505050505050610a72565b6020890151613d27906001612dd8565b60208a0181905260a780549091908110613d3d57fe5b60009182526020918290206040805160a0810182526004909302909101805460808401908152835281518085018352600182015481529383019390935260028301549082015260039091015460608201529350613d998961426a565b955084846040015111613dcb57613dc4613dbd613db68588612dd8565b88906143c2565b8290613f1c565b9050613e15565b6000613de4856040015185612dd890919063ffffffff16565b9050613dfa613df388836143c2565b8390613f1c565b9150613e0683826131d7565b92508460400151935050613cf7565b613e1f81896143de565b9998505050505050505050565b60ff16600a0a90565b6000613e3f614470565b60208301518351613e4f9161372c565b9050613e59614470565b613e6e61105086613e68612fc9565b90613f1c565b9050613e78614470565b613e8d61103387613e87612fc9565b90613f39565b90506000613e9b8884613278565b60000b13158015613eb957506000613eb38883613278565b60000b12155b15613eca5760009350505050610d51565b5060019695505050505050565b6000610d51838360126143fa565b60008183613f065760405162461bcd60e51b8152600401610aef91906149f5565b506000838581613f1257fe5b0495945050505050565b613f24614470565b613f2c614470565b82518451612ee6916131d7565b613f41614470565b613f49614470565b82518451612ee691612dd8565b600054610100900460ff1680613f6f5750613f6f6134dd565b80613f7d575060005460ff16155b613f995760405162461bcd60e51b8152600401610aef90614d4d565b600054610100900460ff16158015613561576000805460ff1961ff00199091166101001716600117905580156113cf576000805461ff001916905550565b600054610100900460ff1680613ff05750613ff06134dd565b80613ffe575060005460ff16155b61401a5760405162461bcd60e51b8152600401610aef90614d4d565b600054610100900460ff16158015614045576000805460ff1961ff0019909116610100171660011790555b600061404f612f29565b603380546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35080156113cf576000805461ff001916905550565b60006140bb614470565b60008560018111156140c957fe5b1461410b576040805160208101909152609e548152614106906140ec9085613f39565b6040805160208101909152609d548152612ce69087613f1c565b614143565b6040805160208101909152609e548152614143906141299085613f1c565b6040805160208101909152609d548152612ce69087613f39565b6040805160208101909152609f54815260a78054929350613383928492919061416d906001612dd8565b8154811061417757fe5b60009182526020918290206040805160a081018252600490930290910180546080840190815283528151808501835260018201548152938301939093526002830154908201526003909101546060820152613e35565b6000610d5183836012614412565b6000816141fa5760405162461bcd60e51b8152600401610aef906150f7565b8160001914801561420e5750600160ff1b83145b1561422b5760405162461bcd60e51b8152600401610aef90614d9b565b600082848161423657fe5b05949350505050565b614247614470565b61424f614470565b82518451612ee69161442b565b6000610d5183836012614439565b614272614470565b61427a6144e1565b60a783602001518154811061428b57fe5b600091825260208083206040805160a081018252600490940290910180546080850190815284528151808401835260018201548152928401929092526002820154908301526003015460608201529150835160018111156142e857fe5b141561430657602081015181516142fe9161372c565b915050610b6a565b60018351600181111561431557fe5b14156143aa5761432c836040015160200151612f3f565b614338576142fe61338c565b6000836040015160400151600181111561434e57fe5b141561437157604083015180516020918201518351928401516142fe9390610e24565b6001836040015160400151600181111561438757fe5b14156143aa57604083015180516020918201518351928401516142fe9390611740565b60405162461bcd60e51b8152600401610aef90614aa1565b6143ca614470565b6143d2614470565b8351612ee6908461323e565b6143e6614470565b6143ee614470565b8351612ee690846131fc565b6000610eb561440883613e2c565b6113bf868661323e565b6000610eb5836113bf61442485613e2c565b879061323e565b6000610d5183836012614458565b6000610eb58361445261444b85613e2c565b8790613b0a565b906141db565b6000610eb561446683613e2c565b6144528686613b0a565b6040518060200160405280600081525090565b6040518060800160405280614496614470565b81526020016144a3614470565b81526020016144b0614470565b81526020016144bd614470565b905290565b60408051606081018252600080825260208201529081016144bd614515565b60405180608001604052806144f4614470565b8152602001614501614470565b815260200160008152602001600081525090565b60408051606081019091528060008152602001614530614470565b815260200160006144bd565b60006020828403121561454d578081fd5b50919050565b600060208284031215614564578081fd5b61456e60206151da565b9135825250919050565b600060208284031215614589578081fd5b8135610d518161520b565b6000602082840312156145a5578081fd5b81358015158114610d51578182fd5b6000806000606084860312156145c8578182fd5b83356145d381615220565b92506145e2856020860161453c565b91506145f1856040860161453c565b90509250925092565b6000806000806080858703121561460f578081fd5b843561461a81615220565b9350614629866020870161453c565b9250614638866040870161453c565b91506060850135801515811461464c578182fd5b939692955090935050565b60008060408385031215614669578182fd5b823561467481615220565b91506146838460208501614553565b90509250929050565b600080600080608085870312156146a1578384fd5b84356146ac81615220565b93506146bb8660208701614553565b92506146ca8660408701614553565b91506146d98660608701614553565b905092959194509250565b6000806000606084860312156146f8578283fd5b833561470381615220565b925060208401356147138161520b565b929592945050506040919091013590565b600060208284031215614735578081fd5b610d51838361453c565b60008060408385031215614751578182fd5b61475b848461453c565b9150614683846020850161453c565b60006020828403121561477b578081fd5b610d518383614553565b600060208284031215614796578081fd5b6147a060206151da565b9151825250919050565b600080604083850312156147bc578182fd5b6146748484614553565b6000806000606084860312156147da578081fd5b6147e48585614553565b92506147f38560208601614553565b91506145f18560408601614553565b600060208284031215614813578081fd5b5035919050565b60006020828403121561482b578081fd5b5051919050565b60008060408385031215614844578182fd5b50508035926020909101359150565b6000806000806000806000806000806000806101808d8f03121561487557898afd5b8c359b5060208d01359a5060408d0135995060608d0135985060808d013561489c8161520b565b975060a08d01356148ac8161520b565b965060c08d01356148bc8161520b565b955060e08d013594506101008d01356148d48161520b565b93506101208d013592506101408d013591506101608d01356148f58161520b565b809150509295989b509295989b509295989b565b6001600160a01b0391909116815260200190565b6001600160a01b03841681526060810161493684615201565b602082019390935260400152919050565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b918252602082015260400190565b6080810161498f86615201565b94815292516020840152905160408301525160609091015290565b606081016149b785615201565b938152602081019290925260409091015290565b606081016149d885615201565b9381526001600160a01b0392909216602083015260409091015290565b6000602080835283518082850152825b81811015614a2157858101830151858201604001528201614a05565b81811115614a325783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601590820152746d756c7469706c6965722063616e2774206265203160581b604082015260600190565b60208082526010908201526f34b63632b3b0b61037b832b930ba37b960811b604082015260600190565b6020808252601490820152733737ba1039bab83837b93a32b21037b83a34b7b760611b604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526019908201527f63616e206e6f742073657420696e74657276616c20746f203000000000000000604082015260600190565b6020808252601a908201527f63616c6c6572206973206e6f7420636f756e7465725061727479000000000000604082015260600190565b60208082526021908201527f5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252601290820152711bdd995c881d1c98591a5b99c81b1a5b5a5d60721b604082015260600190565b6020808252601c908201527f696c6c6567616c206c6971756964697479206d756c7469706c69657200000000604082015260600190565b6020808252600f908201526e0d2dcc6dee4e4cac6e840d2dcc8caf608b1b604082015260600190565b6020808252601590820152740756e6465726c79696e67207072696365206973203605c1b604082015260600190565b6020808252600f908201526e696e76616c6964206164647265737360881b604082015260600190565b6020808252601a908201527f6f7261636c652070726963652063616e2774206265207a65726f000000000000604082015260600190565b6020808252601f908201527f7072696365206973206f76657220666c756374756174696f6e206c696d697400604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526021908201527f5369676e6564536166654d6174683a206469766973696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526014908201527331b0b63632b91034b9903737ba1036b4b73a32b960611b604082015260600190565b6020808252601d908201527f4c657373207468616e206d696e696d616c2071756f746520746f6b656e000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252601c908201527f4c657373207468616e206d696e696d616c206261736520746f6b656e00000000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526027908201527f5369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f604082015266766572666c6f7760c81b606082015260800190565b6020808252600d908201526c696e76616c696420726174696f60981b604082015260600190565b602080825260139082015272195e18da185b99d9481dd85cc818db1bdcd959606a1b604082015260600190565b6020808252601d908201527f4d6f7265207468616e206d6178696d616c2071756f746520746f6b656e000000604082015260600190565b6020808252601c908201527f4d6f7265207468616e206d6178696d616c206261736520746f6b656e00000000604082015260600190565b60208082526018908201527f736574746c652066756e64696e6720746f6f206561726c790000000000000000604082015260600190565b602080825260169082015275696c6c6567616c2070726963652066656564206b657960501b604082015260600190565b6020808252600d908201526c1a5b9d985b1a59081a5b9c1d5d609a1b604082015260600190565b60208082526024908201527f5369676e6564536166654d6174683a207375627472616374696f6e206f766572604082015263666c6f7760e01b606082015260800190565b602080825260149082015273696e76616c6964206f7261636c6520707269636560601b604082015260600190565b6020808252818101527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604082015260600190565b815151815260208083015151908201526040808301515190820152606091820151519181019190915260800190565b9035815260200190565b9051815260200190565b9151825251602082015260400190565b93518452915160208401526040830152606082015260800190565b9283526020830191909152604082015260600190565b9586526020860194909452604085019290925260608401526080830152151560a082015260c00190565b60405181810167ffffffffffffffff811182821017156151f957600080fd5b604052919050565b600281106113cf57fe5b6001600160a01b03811681146113cf57600080fd5b600281106113cf57600080fdfe4d69786564446563696d616c3a2075696e742076616c756520697320626967676572207468616e205f494e543235365f4d4158a26469706673582212203ee68a2d022332a70ef29134324f5224abcecd69beaf731aaf57e5a1b6f7a14064736f6c634300060c0033

Deployed ByteCode Sourcemap

66120:46446:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91234:107;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;70469:44;;;:::i;:::-;;;;;;;:::i;70390:45::-;;;:::i;92232:154::-;;;:::i;:::-;;;;;;;:::i;91646:192::-;;;:::i;:::-;;;;;;;:::i;69620:53::-;;;:::i;110679:1575::-;;;;;;:::i;:::-;;:::i;70107:41::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;:::i;91846:243::-;;;;;;:::i;:::-;;:::i;91493:145::-;;;:::i;90029:204::-;;;;;;:::i;:::-;;:::i;86719:152::-;;;;;;:::i;:::-;;:::i;:::-;;81002:1234;;;;;;:::i;:::-;;:::i;69248:46::-;;;:::i;70348:35::-;;;:::i;91349:136::-;;;:::i;89750:159::-;;;:::i;87554:282::-;;;;;;:::i;:::-;;:::i;69090:52::-;;;:::i;94409:506::-;;;;;;:::i;:::-;;:::i;70157:35::-;;;:::i;92394:162::-;;;:::i;79216:1778::-;;;;;;:::i;:::-;;:::i;70064:36::-;;;:::i;90863:165::-;;;:::i;:::-;;;;;;;;:::i;69899:36::-;;;:::i;94177:224::-;;;;;;:::i;:::-;;:::i;85021:187::-;;;;;;:::i;:::-;;:::i;88186:282::-;;;;;;:::i;:::-;;:::i;85436:245::-;;;;;;:::i;:::-;;:::i;93182:132::-;;;:::i;25112:148::-;;;:::i;86997:199::-;;;;;;:::i;:::-;;:::i;86188:184::-;;;;;;:::i;:::-;;:::i;70250:27::-;;;:::i;69942:37::-;;;:::i;85853:221::-;;;;;;:::i;:::-;;:::i;92712:154::-;;;:::i;24470:79::-;;;:::i;70284:25::-;;;:::i;74097:203::-;;;;;;:::i;:::-;;:::i;69473:47::-;;;:::i;94923:506::-;;;;;;:::i;:::-;;:::i;93473:536::-;;;:::i;:::-;;;;;;;:::i;84032:121::-;;;;;;:::i;:::-;;:::i;74757:1516::-;;;;;;:::i;:::-;;:::i;84661:163::-;;;;;;:::i;:::-;;:::i;70442:20::-;;;:::i;112262:301::-;;;;;;:::i;:::-;;:::i;71064:2602::-;;;;;;:::i;:::-;;:::i;69986:34::-;;;:::i;69574:39::-;;;:::i;92874:148::-;;;:::i;86486:133::-;;;;;;:::i;:::-;;:::i;89352:283::-;;;;;;:::i;:::-;;:::i;76878:381::-;;;;;;:::i;:::-;;:::i;90360:144::-;;;:::i;70027:30::-;;;:::i;88752:283::-;;;;;;:::i;:::-;;:::i;69527:40::-;;;:::i;92564:140::-;;;:::i;92097:127::-;;;:::i;77449:1759::-;;;:::i;93030:144::-;;;:::i;73779:212::-;;;;;;:::i;:::-;;:::i;107631:2984::-;;;;;;:::i;:::-;;:::i;90561:164::-;;;;;;:::i;:::-;;:::i;69707:48::-;;;:::i;25415:244::-;;;;;;:::i;:::-;;:::i;82343:1528::-;;;:::i;84294:113::-;;;;;;:::i;:::-;;:::i;70316:25::-;;;:::i;70199:44::-;;;:::i;93322:143::-;;;:::i;91234:107::-;91310:16;:23;91234:107;:::o;70469:44::-;;;-1:-1:-1;;;;;70469:44:0;;:::o;70390:45::-;;;;:::o;92232:154::-;92298:22;;:::i;:::-;92340:13;;;;;;;;;-1:-1:-1;;;;;92340:13:0;-1:-1:-1;;;;;92340:36:0;;:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;92333:45;;92232:154;:::o;91646:192::-;91713:31;;:::i;:::-;91764:25;91790:32;;:39;;91827:1;91790:36;:39::i;:::-;91764:66;;;;;;;;;;;;;;;;;91757:73;;;;;;;;91764:66;;;;;;;91757:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;91757:73:0;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;91646:192:0;:::o;69620:53::-;;;;:::o;110679:1575::-;110858:34;;:::i;:::-;111374:51;;:::i;:::-;111440:28;;;;;;;;;:17;:28;;;:30;;:28;:30::i;:::-;111436:723;;;111640:21;;;;;;;;;:17;:21;;;111506:272;;111549:214;;111598:19;;111640:23;;:21;:23::i;:::-;111686:18;111727:17;111549:26;:214::i;:::-;111506:24;:272::i;:::-;111487:291;;111436:723;;;111830:317;-1:-1:-1;;111830:285:0;111891:209;111940:14;111977:23;:17;:21;;;;;;;;;;;;;;;;;;:23::i;:::-;112023:18;112064:17;111891:26;:209::i;111830:285::-;:313;;:317::i;:::-;111811:336;;111436:723;112178:45;;;;;;;;;112202:20;112178:45;;;:23;;;;;;;;:18;:23;;;:68;;112229:16;;112178:45;;:23;;:45::i;:::-;:50;;:68::i;:::-;112171:75;;;110679:1575;;;;;:::o;70107:41::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;70107:41:0;;:::o;91846:243::-;91927:31;;:::i;:::-;91983:25;:32;91979:36;;91971:64;;;;-1:-1:-1;;;91971:64:0;;;;;;;:::i;:::-;;;;;;;;;92053:25;92079:1;92053:28;;;;;;;;;;;;;;;;;92046:35;;;;;;;;92053:28;;;;;;;92046:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;92046:35:0;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;91846:243:0;;;;:::o;91493:145::-;91558:34;;:::i;:::-;-1:-1:-1;91605:25:0;;;;;;;;;91612:18;91605:25;;;91493:145;:::o;90029:204::-;90110:22;;:::i;:::-;90152:73;;;;;;;;;;90168:9;;90191:12;;-1:-1:-1;;;90168:56:0;;;90152:73;;;;-1:-1:-1;;;;;90168:9:0;;:22;;:56;;90205:18;90168:56;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90152:73;;90145:80;90029:204;-1:-1:-1;;90029:204:0:o;86719:152::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;86792:23:0;::::1;86784:51;;;;-1:-1:-1::0;;;86784:51:0::1;;;;;;;:::i;:::-;86846:5;:17:::0;;-1:-1:-1;;;;;;86846:17:0::1;-1:-1:-1::0;;;;;86846:17:0;;;::::1;::::0;;;::::1;::::0;;86719:152::o;81002:1234::-;81248:34;;:::i;:::-;81299:25;:16;:23;:25::i;:::-;81295:86;;-1:-1:-1;81353:16:0;81346:23;;81295:86;81393:20;81443:1;81416:24;:16;:22;:24::i;:::-;:28;:43;;81454:5;81416:43;;;81447:4;81416:43;81393:66;;81595:34;;:::i;:::-;81645:226;81690:15;:54;;81725:19;81690:54;;;81708:14;81690:54;81763:22;:16;:20;:22::i;:::-;81804:17;81840:16;81645:26;:226::i;:::-;81595:276;;81951:47;;:::i;:::-;82014:140;82057:82;82071:15;:54;;82111:14;82071:54;;;82089:19;82071:54;82127:11;82057:13;:82::i;82014:140::-;81951:203;;82172:56;82195:15;:32;;-1:-1:-1;;82195:32:0;;;82213:1;82195:32;82172:12;;:22;:56::i;:::-;82165:63;;;;;81002:1234;;;;;;:::o;69248:46::-;;;;:::o;70348:35::-;;;;:::o;91349:136::-;91445:25;:32;91349:136;:::o;89750:159::-;89810:22;;:::i;:::-;89852:49;;;;;;;;;;89868:9;;89887:12;;-1:-1:-1;;;89868:32:0;;;89852:49;;;;-1:-1:-1;;;;;89868:9:0;;:18;;:32;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;89852:49;;89845:56;-1:-1:-1;89750:159:0;:::o;87554:282::-;87694:22;;:::i;:::-;87741:87;87768:4;87774:17;87793:22;87817:10;87741:26;:87::i;69090:52::-;;;;:::o;94409:506::-;94660:22;;:::i;:::-;94715:13;;:192;;-1:-1:-1;;;94715:192:0;;-1:-1:-1;;;;;94715:13:0;;;;:39;;:192;;94773:4;;94796:17;;94832:21;;94872:20;;94715:192;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;94695:212;;94409:506;;;;;;;:::o;70157:35::-;;;-1:-1:-1;;;;;70157:35:0;;:::o;92394:162::-;92464:22;;:::i;:::-;92506:13;;;;;;;;;-1:-1:-1;;;;;92506:13:0;-1:-1:-1;;;;;92506:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79216:1778;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;79443:22:::1;:13;:11;:13::i;:::-;:20;:22::i;:::-;79410:29;:27;;::::0;;::::1;::::0;::::1;:20:::0;:27:::1;:::i;:29::-;:55;;79402:89;;;;-1:-1:-1::0;;;79402:89:0::1;;;;;;;:::i;:::-;79605:70;::::0;;::::1;::::0;::::1;::::0;;;79635:17:::1;79605:70:::0;;;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;79654:20:::0;79605:70:::1;:::i;:::-;:29;:70::i;:::-;79751:45;;;::::0;;::::1;::::0;::::1;79773:22:::0;79751:45:::1;:::i;:::-;:21;:45::i;:::-;79848:54;;:::i;:::-;-1:-1:-1::0;79848:74:0::1;::::0;;::::1;::::0;::::1;::::0;;;79905:17:::1;79848:74:::0;;;79933:53:::1;;:::i;:::-;-1:-1:-1::0;79933:72:0::1;::::0;;::::1;::::0;::::1;::::0;;;79989:16:::1;79933:72:::0;;;80016:58:::1;;:::i;:::-;-1:-1:-1::0;80016:78:0::1;::::0;;::::1;::::0;::::1;::::0;;;80077:17:::1;80016:78:::0;;;80157:58:::1;;;::::0;;::::1;::::0;::::1;80194:20:::0;80157:58:::1;:::i;:::-;:31:::0;;:36:::1;:58::i;:::-;80137:78:::0;:17:::1;:78:::0;80245:57:::1;;;::::0;;::::1;::::0;::::1;80281:20:::0;80245:57:::1;:::i;:::-;:30:::0;;:35:::1;:57::i;:::-;80226:76:::0;:16:::1;:76:::0;80335:176:::1;80386:23:::0;80424:31;80470:30;80335:36:::1;:176::i;:::-;80315:196:::0;:17:::1;:196:::0;;;80597:261:::1;::::0;;;;;;;80661:18:::1;80597:261:::0;::::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;::::1;::::0;;80717:17:::1;80597:261:::0;;;;;;::::1;::::0;;;;;;;::::1;::::0;;80771:16:::1;80597:261:::0;;;-1:-1:-1;;;80597:261:0;;;;;;;::::1;::::0;;;;;;;;;;;80552:25:::1;:317:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;80552:317:0;;;;;;;;::::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;;;;;;;;;;;;;;80904:24;;;;::::1;::::0;;;;;;80887:99:::1;::::0;80904:26:::1;::::0;:24:::1;:26::i;:::-;80932:23;::::0;;::::1;::::0;::::1;::::0;;;:16:::1;:23:::0;;;:25:::1;::::0;:23:::1;:25::i;:::-;80959:24;::::0;;::::1;::::0;::::1;::::0;;;:18:::1;:24:::0;;;:26:::1;::::0;:24:::1;:26::i;:::-;80887:99;;;;;;;;:::i;:::-;;;;;;;;24752:1;;;79216:1778:::0;;:::o;70064:36::-;;;;:::o;90863:165::-;90917:22;;:::i;:::-;90941;;:::i;:::-;-1:-1:-1;;90976:44:0;;;;;;;;;90984:17;90976:44;;;;;;;;;;;91003:16;90976:44;;;90863:165;:::o;69899:36::-;;;;:::o;94177:224::-;94306:22;;:::i;:::-;94353:13;;:40;;-1:-1:-1;;;94353:40:0;;-1:-1:-1;;;;;94353:13:0;;;;:21;;:40;;94375:17;;94353:40;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;85021:187::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;85112:14;85104:52:::1;;;;-1:-1:-1::0;;;85104:52:0::1;;;;;;;:::i;:::-;85167:21;:33:::0;85021:187::o;88186:282::-;88326:22;;:::i;:::-;88373:87;88400:4;88406:16;88424:23;88449:10;88373:26;:87::i;85436:245::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;85499:4:::1;::::0;::::1;-1:-1:-1::0;;;85499:4:0;;::::1;;:13;;::::0;::::1;;;85495:26;;;85514:7;;85495:26;85533:4;:12:::0;;;::::1;::::0;::::1;-1:-1:-1::0;;;85533:12:0::1;-1:-1:-1::0;;;;85533:12:0;;::::1;::::0;;;::::1;::::0;;;85556:118:::1;;85600:62;85654:7;85600:49;85641:7;85600:36;85622:13;;85600:17;:15;:17::i;:::-;:21:::0;::::1;:36::i;:::-;:40:::0;::::1;:49::i;:::-;:53:::0;::::1;:62::i;:::-;85582:15;:80:::0;85556:118:::1;85436:245:::0;:::o;93182:132::-;93237:22;;:::i;:::-;93279:13;;;;;;;;;-1:-1:-1;;;;;93279:13:0;-1:-1:-1;;;;;93279:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25112:148;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;25203:6:::1;::::0;25182:40:::1;::::0;25219:1:::1;::::0;-1:-1:-1;;;;;25203:6:0::1;::::0;25182:40:::1;::::0;25219:1;;25182:40:::1;25233:6;:19:::0;;-1:-1:-1;;;;;;25233:19:0::1;::::0;;25112:148::o;86997:199::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;87083:28:0;::::1;87075:56;;;;-1:-1:-1::0;;;87075:56:0::1;;;;;;;:::i;:::-;87142:13;:46:::0;;-1:-1:-1;;;;;;87142:46:0::1;-1:-1:-1::0;;;;;87142:46:0;;;::::1;::::0;;;::::1;::::0;;86997:199::o;86188:184::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;86275:24:0;::::1;86267:52;;;;-1:-1:-1::0;;;86267:52:0::1;;;;;;;:::i;:::-;86330:9;:34:::0;;-1:-1:-1;;;;;;86330:34:0::1;-1:-1:-1::0;;;;;86330:34:0;;;::::1;::::0;;;::::1;::::0;;86188:184::o;70250:27::-;;;-1:-1:-1;;;;;70250:27:0;;:::o;69942:37::-;;;;:::o;85853:221::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;86000:1:::1;85960:36;85982:13;:11;:13::i;:::-;85960:17:::0;;:21:::1;:36::i;:::-;:41;;;;85952:67;;;;-1:-1:-1::0;;;85952:67:0::1;;;;;;;:::i;:::-;86030:36:::0;:16:::1;:36:::0;85853:221::o;92712:154::-;92778:22;;:::i;:::-;92820:13;;;;;;;;;-1:-1:-1;;;;;92820:13:0;-1:-1:-1;;;;;92820:36:0;;:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24470:79;24535:6;;-1:-1:-1;;;;;24535:6:0;24470:79;:::o;70284:25::-;;;-1:-1:-1;;;;;70284:25:0;;:::o;74097:203::-;68053:12;:10;:12::i;:::-;68035:13;;-1:-1:-1;;;;;68035:13:0;;;68027:38;;;68019:71;;;;-1:-1:-1;;;68019:71:0;;;;;;;:::i;:::-;74250:13:::1;::::0;:42:::1;::::0;-1:-1:-1;;;74250:42:0;;-1:-1:-1;;;;;74250:13:0;;::::1;::::0;:18:::1;::::0;:42:::1;::::0;74269:5;;74276:7;;74285:6;;74250:42:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;74097:203:::0;;;:::o;69473:47::-;;;;:::o;94923:506::-;95174:22;;:::i;:::-;95229:13;;:192;;-1:-1:-1;;;95229:192:0;;-1:-1:-1;;;;;95229:13:0;;;;:40;;:192;;95288:4;;95311:16;;95346:21;;95386:20;;95229:192;;;:::i;93473:536::-;93534:4;93551:34;;:::i;:::-;93588:20;:18;:20::i;:::-;93551:57;;93650:1;93627:20;:11;:18;:20::i;:::-;:24;93619:58;;;;-1:-1:-1;;;93619:58:0;;;;;;;:::i;:::-;93688:34;;:::i;:::-;93725:14;:12;:14::i;:::-;93688:51;;93750:43;;:::i;:::-;93809:79;:73;93870:11;93809:55;93852:11;93809:37;93834:11;93809:24;:37::i;:::-;:42;;:55::i;:::-;:60;;:73::i;:::-;:77;:79::i;:::-;93750:138;;93941:45;:13;;;;;;;;;-1:-1:-1;;;;;93941:13:0;-1:-1:-1;;;;;93941:34:0;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:45::-;93908:29;:20;:27;:29::i;:::-;:78;;:93;;93996:5;93908:93;;;93989:4;93908:93;93901:100;;;;;93473:536;:::o;84032:121::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;84110:8:::1;:35:::0;;-1:-1:-1;;;;;;84110:35:0::1;-1:-1:-1::0;;;;;84110:35:0;;;::::1;::::0;;;::::1;::::0;;84032:121::o;74757:1516::-;74965:22;;:::i;:::-;67688:4;;-1:-1:-1;;;67688:4:0;;;;67680:36;;;;-1:-1:-1;;;67680:36:0;;;;;;;:::i;:::-;67915:12:::1;:10;:12::i;:::-;67902:8;::::0;-1:-1:-1;;;;;67902:8:0;;::::1;67894:33:::0;::::1;;67886:72;;;;-1:-1:-1::0;;;67886:72:0::1;;;;;;;:::i;:::-;75004:26:::2;:24;;::::0;;::::2;::::0;::::2;:17:::0;:24:::2;:::i;:26::-;75000:85;;75059:14;:12;:14::i;:::-;75052:21;;;;75000:85;75107:19;75099:4;:27;;;;;;;;;75095:218;;;75221:26;:24;;::::0;;::::2;::::0;::::2;:17:::0;:24:::2;:::i;:26::-;75169:39;::::0;;::::2;::::0;;::::2;::::0;;75192:15:::2;75169:39:::0;;;:22;;;;::::2;::::0;;;:17:::2;:22:::0;;;:48:::2;::::0;:39:::2;::::0;:22:::2;:39::i;:48::-;:78;;75143:158;;;;-1:-1:-1::0;;;75143:158:0::2;;;;;;;:::i;:::-;75325:38;;:::i;:::-;75366;75380:4:::0;75366:38:::2;;::::0;;::::2;::::0;::::2;75386:17:::0;75366:38:::2;:::i;:::-;75325:79:::0;-1:-1:-1;75708:30:0::2;:28;;::::0;;::::2;::::0;::::2;:21:::0;:28:::2;:::i;:30::-;:35:::0;75704:369:::2;;75772:14;75764:4;:22;;;;;;;;;75760:302;;;75843:30;:28;;::::0;;::::2;::::0;::::2;:21:::0;:28:::2;:::i;:30::-;75815:24;:15;:22;:24::i;:::-;:58;;75807:99;;;;-1:-1:-1::0;;;75807:99:0::2;;;;;;;:::i;:::-;75760:302;;;75983:30;:28;;::::0;;::::2;::::0;::::2;:21:::0;:28:::2;:::i;:30::-;75955:24;:15;:22;:24::i;:::-;:58;;75947:99;;;;-1:-1:-1::0;;;75947:99:0::2;;;;;;;:::i;:::-;76085:62;76099:4:::0;76085:62:::2;;::::0;;::::2;::::0;::::2;76105:17:::0;76085:62:::2;:::i;:::-;76124:15;76141:5;76085:13;:62::i;:::-;76163:69;76173:4:::0;76179:26:::2;:24;;::::0;;::::2;::::0;::::2;:17:::0;:24:::2;:::i;:26::-;76207:24;:15;:22;:24::i;:::-;76163:69;;;;;;;;:::i;:::-;;;;;;;;76250:15:::0;74757:1516;-1:-1:-1;;;;74757:1516:0:o;84661:163::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;84770:46;:21:::1;:46:::0;84661:163::o;70442:20::-;;;-1:-1:-1;;;;;70442:20:0;;:::o;112262:301::-;67915:12;:10;:12::i;:::-;67902:8;;-1:-1:-1;;;;;67902:8:0;;;67894:33;;;67886:72;;;;-1:-1:-1;;;67886:72:0;;;;;;;:::i;:::-;112489:22:::1;::::0;;::::1;::::0;::::1;::::0;;;:17:::1;:22:::0;;;:66:::1;::::0;112535:19;;112489:40:::1;::::0;112512:16;112489:22:::1;:40::i;:::-;:45:::0;::::1;:66::i;:::-;112469:86:::0;:17:::1;:86:::0;-1:-1:-1;;112262:301:0:o;71064:2602::-;20809:13;;;;;;;;:33;;;20826:16;:14;:16::i;:::-;20809:50;;;-1:-1:-1;20847:12:0;;;;20846:13;20809:50;20801:109;;;;-1:-1:-1;;;20801:109:0;;;;;;;:::i;:::-;20923:19;20946:13;;;;;;20945:14;20970:101;;;;21005:13;:20;;-1:-1:-1;;;;21005:20:0;;;;;21040:19;21021:4;21040:19;;;20970:101;71565:23;;;::::1;::::0;:65:::1;;-1:-1:-1::0;71609:21:0;;::::1;71565:65;:108;;;;-1:-1:-1::0;71651:22:0;;::::1;71565:108;:148;;;;-1:-1:-1::0;71694:19:0;;::::1;71565:148;:202;;;;-1:-1:-1::0;;;;;;71734:33:0;::::1;::::0;::::1;71565:202;:255;;;;-1:-1:-1::0;;;;;;71788:32:0;::::1;::::0;::::1;71565:255;:313;;;;-1:-1:-1::0;;;;;;71841:37:0;::::1;::::0;::::1;71565:313;:371;;;;-1:-1:-1::0;;;;;;71899:37:0;::::1;::::0;::::1;71565:371;:417;;;;-1:-1:-1::0;;;;;;71957:25:0;::::1;::::0;::::1;71565:417;71543:480;;;;-1:-1:-1::0;;;71543:480:0::1;;;;;;;:::i;:::-;72034:16;:14;:16::i;:::-;72083:35;::::0;;::::1;::::0;;::::1;::::0;;;;;;72063:17:::1;:55:::0;;;72148:34;;;;::::1;::::0;;;;;72129:16:::1;:53:::0;;;72211:33;;;;::::1;::::0;;;;;72193:15:::1;:51:::0;;;72274:34;;;;::::1;::::0;;;;;72255:16:::1;:53:::0;;;72343:39;;;;::::1;::::0;;;;;;72319:21:::1;:63:::0;;;72393:13:::1;:30:::0;;;72456:21:::1;72409:14:::0;-1:-1:-1;72456:18:0::1;:21::i;:::-;72434:19;:43:::0;72512:7:::1;72488:21;:31:::0;72530:12:::1;:28:::0;;;72569:10:::1;:43:::0;;-1:-1:-1;;;;;;72569:43:0;;::::1;-1:-1:-1::0;;;;;72569:43:0;;::::1;::::0;;;::::1;::::0;;;72623:9:::1;:22:::0;;;::::1;::::0;;::::1;;::::0;;72656:8:::1;:20:::0;;;::::1;::::0;;::::1;;::::0;;72687:13:::1;:30:::0;;;::::1;::::0;;::::1;;::::0;;72728:13:::1;:30:::0;;;;::::1;::::0;;::::1;::::0;;;::::1;::::0;;72794:27:::1;::::0;;::::1;::::0;::::1;::::0;;;72810:10:::1;72794:27:::0;;;;72769:22:::1;:52:::0;72840:12:::1;:10;:12::i;:::-;72832:5;:20:::0;;-1:-1:-1;;;;;;72832:20:0::1;-1:-1:-1::0;;;;;72832:20:0;;::::1;;::::0;;72865:13:::1;::::0;:60:::1;::::0;-1:-1:-1;;;72865:60:0;;:13;::::1;::::0;:40:::1;::::0;:60:::1;::::0;72914:4:::1;::::0;72921:3:::1;::::0;72865:60:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;72936:13:0::1;::::0;:74:::1;::::0;-1:-1:-1;;;72936:74:0;;-1:-1:-1;;;;;72936:13:0;;::::1;::::0;-1:-1:-1;72936:24:0::1;::::0;-1:-1:-1;72936:74:0::1;::::0;72969:4:::1;::::0;72936:13:::1;::::0;73007:2:::1;::::0;72936:74:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;73021:13:0::1;::::0;:73:::1;::::0;-1:-1:-1;;;73021:73:0;;-1:-1:-1;;;;;73021:13:0;;::::1;::::0;-1:-1:-1;73021:24:0::1;::::0;-1:-1:-1;73021:73:0::1;::::0;73054:4:::1;::::0;73021:13;;73091:2:::1;::::0;73021:73:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;73107:25;73152:266;;;;;;;;73216:20;:18;:20::i;:::-;73152:266:::0;;::::1;::::0;;::::1;::::0;;::::1;::::0;;73327:17:::1;73152:266:::0;;;;;::::1;::::0;;;;;;;;::::1;::::0;;73273:16:::1;73152:266:::0;;;;;;;;;73382:20:::1;:18;:20::i;:::-;73152:266:::0;;73107:322;;::::1;::::0;;::::1;::::0;;-1:-1:-1;73107:322:0;;;::::1;::::0;;;;;;;::::1;::::0;;::::1;;::::0;;;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;::::1;::::0;;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;::::1;::::0;;::::1;::::0;73462:87;;;;;;;73478:17:::1;73462:87:::0;::::1;::::0;::::1;::::0;;;;;;;;;::::1;::::0;;73497:16:::1;73462:87:::0;;;;;::::1;::::0;;;;73440:16:::1;::::0;73462:87;-1:-1:-1;;73515:17:0::1;:15;:17::i;:::-;73462:87;;;;73534:14;:12;:14::i;:::-;73462:87:::0;;73440:110;;::::1;::::0;;::::1;::::0;;-1:-1:-1;73440:110:0;;;::::1;::::0;;;;;;;::::1;::::0;;::::1;;::::0;;;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;::::1;::::0;73585:24;;;;::::1;::::0;;:17:::1;:24:::0;;;73566:92:::1;::::0;73585:26:::1;::::0;:24:::1;:26::i;:::-;73613:23;::::0;;::::1;::::0;::::1;::::0;;;:16:::1;:23:::0;;;:25:::1;::::0;:23:::1;:25::i;:::-;73640:17;:15;:17::i;:::-;73566:92;;;;;;;;:::i;:::-;;;;;;;;21101:14:::0;21097:68;;;21148:5;21132:21;;-1:-1:-1;;21132:21:0;;;21097:68;71064:2602;;;;;;;;;;;;;:::o;69986:34::-;;;;:::o;69574:39::-;;;;:::o;92874:148::-;92937:22;;:::i;:::-;92979:13;;;;;;;;;-1:-1:-1;;;;;92979:13:0;-1:-1:-1;;;;;92979:33:0;;:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86486:133;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;86580:31;:22:::1;:31:::0;86486:133::o;89352:283::-;89493:22;;:::i;:::-;89540:87;;;;;;;;;89591:17;89540:87;;;;;;;;;;;89610:16;89540:87;;;;;89567:4;;89573:16;;89540:26;:87::i;76878:381::-;77124:22;;:::i;:::-;67688:4;;-1:-1:-1;;;67688:4:0;;;;67680:36;;;;-1:-1:-1;;;67680:36:0;;;;;;;:::i;:::-;67915:12:::1;:10;:12::i;:::-;67902:8;::::0;-1:-1:-1;;;;;67902:8:0;;::::1;67894:33:::0;::::1;;67886:72;;;;-1:-1:-1::0;;;67886:72:0::1;;;;;;;:::i;:::-;77166:85:::2;77181:4:::0;77166:85:::2;;::::0;;::::2;::::0;::::2;77187:16:::0;77166:85:::2;:::i;:::-;;;::::0;;::::2;::::0;::::2;77205:22:::0;77166:85:::2;:::i;:::-;77229:21;77166:14;:85::i;90360:144::-:0;90414:22;;:::i;:::-;90456:40;;;;;;;;;90479:16;90456:40;;;:22;;;;;;;;:17;:22;;;:40;;:22;;:40::i;70027:30::-;;;;:::o;88752:283::-;88893:22;;:::i;:::-;88940:87;;;;;;;;;88991:17;88940:87;;;;;;;;;;;89010:16;88940:87;;;;;88966:4;;88972:17;;88940:25;:87::i;69527:40::-;;;;:::o;92564:140::-;92623:22;;:::i;:::-;92665:13;;;;;;;;;-1:-1:-1;;;;;92665:13:0;-1:-1:-1;;;;;92665:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92097:127;92159:22;;:::i;:::-;-1:-1:-1;92194:22:0;;;;;;;;;92201:15;92194:22;;;92097:127;:::o;77449:1759::-;77527:34;;:::i;:::-;67688:4;;-1:-1:-1;;;67688:4:0;;;;67680:36;;;;-1:-1:-1;;;67680:36:0;;;;;;;:::i;:::-;67915:12:::1;:10;:12::i;:::-;67902:8;::::0;-1:-1:-1;;;;;67902:8:0;;::::1;67894:33:::0;::::1;;67886:72;;;;-1:-1:-1::0;;;67886:72:0::1;;;;;;;:::i;:::-;77603:15:::2;;77582:17;:15;:17::i;:::-;:36;;77574:73;;;;-1:-1:-1::0;;;77574:73:0::2;;;;;;;:::i;:::-;77658:50;;:::i;:::-;77711:20;:18;:20::i;:::-;77658:73;;77742:38;;:::i;:::-;77783:45;77806:21;;77783:22;:45::i;:::-;77742:86;;77971:15;;77929:39;77954:13;;77929:20;;:24;;:39;;;;:::i;:::-;:57;77925:503;;;78180:42;;:::i;:::-;78242:83;78309:15;78242:61;78267:35;78280:21;;78267:12;:35::i;78242:83::-;78180:145;;78358:58;78408:6;78358:32;78376:13;;78358:7;:17;;:32;;;;:::i;:::-;:42:::0;::::2;:58::i;:::-;78340:76;;77925:503;;78507:51;78525:15;78542;78507:17;:51::i;:::-;78679:31;78713:42;78735:19;;78713:17;:15;:17::i;:42::-;78679:76;;78835:34;78872:60;78924:7;78872:47;78911:7;78872:34;78892:13;;78872:15;;:19;;:34;;;;:::i;:60::-;78835:97;;79061:23;79032:26;:52;:133;;79142:23;79032:133;;;79100:26;79032:133;79014:15;:151:::0;-1:-1:-1;79185:15:0;;-1:-1:-1;;;77449:1759:0;:::o;93030:144::-;93091:22;;:::i;:::-;93133:13;;;;;;;;;-1:-1:-1;;;;;93133:13:0;-1:-1:-1;;;;;93133:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73779:212;67688:4;;-1:-1:-1;;;67688:4:0;;;;67680:36;;;;-1:-1:-1;;;67680:36:0;;;;;;;:::i;:::-;68053:12:::1;:10;:12::i;:::-;68035:13;::::0;-1:-1:-1;;;;;68035:13:0;;::::1;68027:38:::0;::::1;;68019:71;;;;-1:-1:-1::0;;;68019:71:0::1;;;;;;;:::i;:::-;73941:13:::2;::::0;:42:::2;::::0;-1:-1:-1;;;73941:42:0;;-1:-1:-1;;;;;73941:13:0;;::::2;::::0;:18:::2;::::0;:42:::2;::::0;73960:5;;73967:7;;73976:6;;73941:42:::2;;;:::i;107631:2984::-:0;107750:12;:10;:12::i;:::-;107741:5;;-1:-1:-1;;;;;107741:5:0;;;:21;;;;:59;;;107788:12;:10;:12::i;:::-;107774:9;;-1:-1:-1;;;;;107774:9:0;;;107766:34;;;107741:59;107733:88;;;;-1:-1:-1;;;107733:88:0;;;;;;;:::i;:::-;107855:1;107840:12;:16;107832:55;;;;-1:-1:-1;;;107832:55:0;;;;;;;:::i;:::-;107922:13;107906:12;;:29;107898:64;;;;-1:-1:-1;;;107898:64:0;;;;;;;:::i;:::-;107978:4;;-1:-1:-1;;;107978:4:0;;;;107977:5;;:39;;-1:-1:-1;107986:23:0;;;;;;;;;:16;:23;;;:25;;:23;:25::i;:::-;:30;107977:39;107973:52;;;108018:7;;107973:52;108037:34;;:::i;:::-;-1:-1:-1;108074:29:0;;;;;;;;;;;;108114:31;;:::i;:::-;108148:40;;;;;;;;;108171:16;108148:40;;;:22;;;;;;;;:17;:22;;;:40;;:22;;:40::i;:::-;108284:27;;;;;;;;;:22;:27;;;108114:74;;-1:-1:-1;108326:1:0;;108221:101;;108284:37;;108114:74;108284:27;:37::i;:::-;108221:58;:52;108264:8;108221:37;108246:11;108221:24;:37::i;:58::-;:62;;:101::i;:::-;:106;;;;108199:176;;;;-1:-1:-1;;;108199:176:0;;;;;;;:::i;:::-;108388:34;;:::i;:::-;108514:75;;;;;;;;;108572:16;108514:75;;;108438:176;;:152;;108514:75;;:52;108557:8;108514:37;108539:11;108514:24;:37::i;:52::-;:57;;:75::i;:::-;108438:52;108481:8;108438:42;:52::i;:176::-;108388:226;;108701:32;;:::i;:::-;108736:40;;;;;;;;;108759:16;108736:40;;;:22;;;;;;;;:17;:22;;;:40;;:22;;:40::i;:::-;108701:75;;108787:15;108805:64;108846:22;:13;:11;:13::i;:22::-;108805:36;:27;:9;108820:11;108805:14;:27::i;:64::-;108787:82;;108880:40;;:::i;:::-;108923:31;;;;;;;;108939:14;:7;:12;:14::i;:::-;108923:31;;108880:74;-1:-1:-1;108965:41:0;;:::i;:::-;109009:33;:9;109024:17;109009:14;:33::i;:::-;108965:77;;109055:40;;:::i;:::-;109098:57;109117:17;109136:18;109098;:57::i;:::-;109055:100;;109166:46;;:::i;:::-;109215:13;;:57;;-1:-1:-1;;;109215:57:0;;-1:-1:-1;;;;;109215:13:0;;;;:42;;:57;;109266:4;;109215:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;109166:106;;109283:40;;:::i;:::-;109326:13;;:54;;-1:-1:-1;;;109326:54:0;;-1:-1:-1;;;;;109326:13:0;;;;:39;;:54;;109374:4;;109326:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;109283:97;-1:-1:-1;109461:60:0;:47;109283:97;109461:23;:5;109472:11;109461:10;:23::i;:::-;:28;;:47::i;:::-;:58;:60::i;:::-;109457:1151;;;109543:227;109574:17;:8;:15;:17::i;:::-;109610:12;109641:20;:11;:18;:20::i;:::-;109680:19;:11;:17;:19::i;:::-;109718:13;:5;:11;:13::i;:::-;109750:5;109543:227;;;;;;;;;;;:::i;:::-;;;;;;;;109457:1151;;;109803:45;;:::i;:::-;109868:68;;;;;;;;;109918:17;109868:68;;;;;:44;109893:18;109868:24;:44::i;:68::-;109974:25;;;;;;;;;:20;:25;;;109803:133;;-1:-1:-1;109974:37:0;;109803:133;109974:25;:37::i;:::-;109951:60;:20;:60;110047:23;;;;;;;;;:18;:23;;;:35;;110071:10;110047:23;:35::i;:::-;110026:56;:18;:56;110097:36;;:16;:36;110148:38;;:17;:38;110224:17;:15;:17::i;:::-;110201:20;:40;110258:20;:18;:20::i;:::-;110293:13;;;;;;;;;-1:-1:-1;;;;;110293:13:0;-1:-1:-1;;;;;110293:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110346:250;110377:17;:8;:15;:17::i;:::-;110413:12;110444:20;:11;:18;:20::i;:::-;110483:43;:35;:11;110500:17;110483:16;:35::i;:43::-;110545:13;:5;:11;:13::i;:::-;110577:4;110346:250;;;;;;;;;;;:::i;:::-;;;;;;;;109457:1151;;107631:2984;;;;;;;;;;;;;:::o;90561:164::-;90632:22;;:::i;:::-;90674:43;90698:18;90674:23;:43::i;69707:48::-;;;;:::o;25415:244::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;25504:22:0;::::1;25496:73;;;;-1:-1:-1::0;;;25496:73:0::1;;;;;;;:::i;:::-;25606:6;::::0;25585:38:::1;::::0;-1:-1:-1;;;;;25585:38:0;;::::1;::::0;25606:6:::1;::::0;25585:38:::1;::::0;25606:6:::1;::::0;25585:38:::1;25634:6;:17:::0;;-1:-1:-1;;;;;;25634:17:0::1;-1:-1:-1::0;;;;;25634:17:0;;;::::1;::::0;;;::::1;::::0;;25415:244::o;82343:1528::-;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;82402:13:::1;;;;;;;;;-1:-1:-1::0;;;;;82402:13:0::1;-1:-1:-1::0;;;;;82402:29:0::1;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;82444:55;;:::i;:::-;82502:36;:34;:36::i;:::-;82444:94;;82629:32;;:::i;:::-;82723:41;::::0;::::1;::::0;82677:40:::1;::::0;::::1;::::0;:88:::1;::::0;:45:::1;:88::i;:::-;82629:136;;82776:64;;:::i;:::-;82903:40;::::0;::::1;::::0;82856:41:::1;::::0;::::1;::::0;:88:::1;::::0;:46:::1;:88::i;:::-;82776:168;;82955:65;;:::i;:::-;83036:71;83077:29;83036:35;83061:9;83036:24;:35::i;:::-;:40:::0;::::1;:71::i;:::-;82955:152;;83364:56;;:::i;:::-;83436:54;::::0;;::::1;::::0;::::1;::::0;;;83472:17:::1;83436:54:::0;;;::::1;::::0;:30;;:35:::1;:54::i;:::-;83628:24;::::0;;::::1;::::0;::::1;::::0;;;:17:::1;:24:::0;;;83364:126;;-1:-1:-1;66653:3:0::1;::::0;83628:26:::1;::::0;:24:::1;:26::i;:::-;:57;83624:165;;;83753:21;::::0;;::::1;::::0;::::1;::::0;;;:17:::1;:21:::0;;;83720:57:::1;::::0;83753:23:::1;::::0;:21:::1;:23::i;:::-;83720:27;:21;:25;:27::i;:::-;:32:::0;::::1;:57::i;:::-;83702:75:::0;:15:::1;:75:::0;83624:165:::1;83801:4;:12:::0;;-1:-1:-1;;;;83801:12:0::1;::::0;;83838:22:::1;::::0;;::::1;::::0;::::1;::::0;;;:15:::1;:22:::0;;;83829:34:::1;::::0;83838:24:::1;::::0;:22:::1;:24::i;:::-;83829:34;;;;;;:::i;84294:113::-:0;24692:12;:10;:12::i;:::-;24682:6;;-1:-1:-1;;;;;24682:6:0;;;:22;;;24674:67;;;;-1:-1:-1;;;24674:67:0;;;;;;;:::i;:::-;84360:13:::1;:39:::0;;-1:-1:-1;;;;;;84360:39:0::1;-1:-1:-1::0;;;;;84360:39:0;;;::::1;::::0;;;::::1;::::0;;84294:113::o;70316:25::-;;;-1:-1:-1;;;70316:25:0;;;;;:::o;70199:44::-;;;-1:-1:-1;;;;;70199:44:0;;:::o;93322:143::-;93386:34;;:::i;:::-;-1:-1:-1;93433:24:0;;;;;;;;;93440:17;93433:24;;;93322:143;:::o;4320:136::-;4378:7;4405:43;4409:1;4412;4405:43;;;;;;;;;;;;;;;;;:3;:43::i;35174:165::-;35241:4;35268:1;35262;:3;;;:7;35258:51;;;-1:-1:-1;35293:4:0;35286:11;;35258:51;-1:-1:-1;35326:5:0;35174:165;;;:::o;35347:269::-;35407:22;;:::i;:::-;35442:24;;:::i;:::-;35481:3;;35487:1;-1:-1:-1;35477:113:0;;;35523:3;;;35519:7;35505:22;;35477:113;;;35574:3;;35560:18;;-1:-1:-1;35560:18:0;35347:269::o;61986:228::-;62107:34;;:::i;:::-;62086:1;61931;:3;;;-1:-1:-1;;;;;61916:18:0;;61936:21;;;;;;;;;;;;;;;;;61908:50;;;;;-1:-1:-1;;;61908:50:0;;;;;;;;:::i;:::-;-1:-1:-1;;62166:40:0::1;::::0;;::::1;::::0;::::1;::::0;;;62201:3;;62166:40;;-1:-1:-1;62166:40:0;61986:228::o;36391:185::-;36467:20;;:::i;:::-;36500:22;;:::i;:::-;36539:3;;:10;;36547:1;36539:7;:10::i;:::-;36533:16;;;36391:185;-1:-1:-1;;;36391:185:0:o;35895:196::-;35980:20;;:::i;:::-;36013:22;;:::i;:::-;36060:3;;36052;;:12;;:7;:12::i;35655:196::-;35740:20;;:::i;:::-;35773:22;;:::i;:::-;35820:3;;35812;;:12;;:7;:12::i;22743:106::-;22831:10;22743:106;:::o;62222:121::-;62299:7;62326;:1;:5;:7::i;:::-;:9;;62222:121;-1:-1:-1;;62222:121:0:o;35067:99::-;35155:3;;35067:99::o;99821:549::-;100011:22;;:::i;:::-;100046:33;;:::i;:::-;100103:26;100090:39;;;100163:16;:23;:30;;:27;:30::i;:::-;100140:20;;;:53;100204:12;;;;100223:4;100204:23;;;;;;;;;;;;;;;;;;;;-1:-1:-1;100238:12:0;;;;;;:24;;:39;;;100288:12;:20;100311:6;100288:29;;;;;;;;;;;;;;;;;;;;-1:-1:-1;100335:27:0;100344:6;100352:9;100335:8;:27::i;:::-;100328:34;99821:549;-1:-1:-1;;;;;;99821:549:0:o;28182:109::-;28220:14;;:::i;:::-;28254:29;;;;;;;;28262:20;28279:2;28262:16;:20::i;106283:664::-;106551:1;106527:21;:13;:19;:21::i;:::-;:25;106523:417;;;106569:52;;:::i;:::-;106641:143;;;;;;;;;106767:16;106641:143;;;106682:56;;;;;;;;66811:3;106682:56;;106641:171;;:143;;;:98;;:13;;:40;:98::i;:171::-;106569:243;-1:-1:-1;106894:1:0;106835:55;:20;106569:243;106835:24;:55::i;:::-;:60;;;;106827:101;;;;-1:-1:-1;;;106827:101:0;;;;;;;:::i;:::-;106523:417;106283:664;;:::o;105394:881::-;105580:1;105546:31;:22;:29;:31::i;:::-;:35;105542:726;;;105612:16;:23;105650:37;;:::i;:::-;105690:16;105713:1;105707:3;:7;105690:25;;;;;;;;;;;;;;;;;105650:65;;;;;;;;105690:25;;;;;;;105650:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;105650:65:0;;;;;;;;;;;-1:-1:-1;105856:14:0;:12;:14::i;:::-;105826;:26;;;:44;:55;;;;;105880:1;105874:3;:7;105826:55;105822:138;;;105919:16;105942:1;105936:3;:7;105919:25;;;;;;;;;;;;;;;;;105902:42;;;;;;;;105919:25;;;;;;;105902:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;105902:42:0;;;;;;;;;;;-1:-1:-1;105822:138:0;106048:40;;;;;;;;;106071:16;106048:40;;;:22;;;;;;;;:17;:22;;;106003:186;;106048:40;;:22;:40::i;:::-;106111:22;106156:14;106003:22;:186::i;:::-;106002:187;105976:280;;;;-1:-1:-1;;;105976:280:0;;;;;;;:::i;29262:173::-;29335:14;;:::i;:::-;29362:16;;:::i;:::-;29404:3;;29395;;:13;;:8;:13::i;65243:108::-;65328:15;65243:108;:::o;3856:181::-;3914:7;3946:5;;;3970:6;;;;3962:46;;;;-1:-1:-1;;;3962:46:0;;;;;;;:::i;6157:132::-;6215:7;6242:39;6246:1;6249;6242:39;;;;;;;;;;;;;;;;;:3;:39::i;5210:471::-;5268:7;5513:6;5509:47;;-1:-1:-1;5543:1:0;5536:8;;5509:47;5580:5;;;5584:1;5580;:5;:1;5604:5;;;;;:10;5596:56;;;;-1:-1:-1;;;5596:56:0;;;;;;;:::i;28569:222::-;28668:3;;28662;;28641:4;;-1:-1:-1;28658:107:0;;;-1:-1:-1;28695:1:0;28688:8;;28658:107;28724:3;;28718;;:9;28714:51;;;-1:-1:-1;;;28744:9:0;;28714:51;-1:-1:-1;28782:1:0;28569:222;;;;:::o;62861:304::-;63013:34;;:::i;:::-;62992:1;61931;:3;;;-1:-1:-1;;;;;61916:18:0;;61936:21;;;;;;;;;;;;;;;;;61908:50;;;;;-1:-1:-1;;;61908:50:0;;;;;;;;:::i;:::-;;63065:36:::1;;:::i;:::-;63133:3:::0;;63118;;:20:::1;::::0;:7:::1;:20::i;:::-;63112:26:::0;;;62861:304;-1:-1:-1;;;;62861:304:0:o;64032:::-;64184:34;;:::i;:::-;64163:1;61931;:3;;;-1:-1:-1;;;;;61916:18:0;;61936:21;;;;;;;;;;;;;;;;;61908:50;;;;;-1:-1:-1;;;61908:50:0;;;;;;;;:::i;:::-;;64236:36:::1;;:::i;:::-;64287:22;64294:14;64306:1;64294:11;:14::i;:::-;64287:1:::0;;:6:::1;:22::i;:::-;64283:26:::0;64032:304;-1:-1:-1;;;;;64032:304:0:o;28083:91::-;28122:14;;:::i;:::-;-1:-1:-1;28156:10:0;;;;;;;;;-1:-1:-1;28156:10:0;;28083:91;:::o;98668:1145::-;98887:14;98879:4;:22;;;;;;;;;98875:662;;;98938:22;;;;;;;;;:17;:22;;;:41;;98961:17;98938:22;:41::i;:::-;98918:61;:17;:61;99013:21;;;;;;;;;:16;:21;;;:39;;99035:16;99013:21;:39::i;:::-;98994:58;:16;:58;99087:22;;;;;;;;;:17;:22;;;:40;;99110:16;99087:22;:40::i;:::-;99067:60;:17;:60;99163:23;;;;;;;;;:18;:23;;;:42;;99187:17;99163:23;:42::i;:::-;99142:63;:18;:63;98875:662;;;99258:22;;;;;;;;;:17;:22;;;:41;;99281:17;99258:22;:41::i;:::-;99238:61;:17;:61;99333:21;;;;;;;;;:16;:21;;;:39;;99355:16;99333:21;:39::i;:::-;99314:58;:16;:58;99407:22;;;;;;;;;:17;:22;;;:40;;99430:16;99407:22;:40::i;:::-;99387:60;:17;:60;99483:23;;;;;;;;;:18;:23;;;:42;;99507:17;99483:23;:42::i;:::-;99462:63;:18;:63;98875:662;99607:21;99602:99;;99645:44;;;;;;;;;99667:21;99645:44;;;;;:21;:44::i;:::-;99785:20;:18;:20::i;:::-;98668:1145;;;;:::o;21265:604::-;21707:4;21818:17;21854:7;21265:604;:::o;24056:129::-;20809:13;;;;;;;;:33;;;20826:16;:14;:16::i;:::-;20809:50;;;-1:-1:-1;20847:12:0;;;;20846:13;20809:50;20801:109;;;;-1:-1:-1;;;20801:109:0;;;;;;;:::i;:::-;20923:19;20946:13;;;;;;20945:14;20970:101;;;;21005:13;:20;;-1:-1:-1;;;;21005:20:0;;;;;21040:19;21021:4;21040:19;;;20970:101;24114:26:::1;:24;:26::i;:::-;24151;:24;:26::i;:::-;21101:14:::0;21097:68;;;21148:5;21132:21;;-1:-1:-1;;21132:21:0;;;24056:129;:::o;65359:102::-;65441:12;65359:102;:::o;96601:2059::-;96812:22;;:::i;:::-;96851:25;:16;:23;:25::i;:::-;96847:84;;96905:14;:12;:14::i;:::-;96898:21;;;;96847:84;97045:19;97037:4;:27;;;;;;;;;97033:167;;;97140:25;:16;:23;:25::i;:::-;97089:38;;;;;;;;;97111:15;97089:38;;;:21;;;;;;;;:16;:21;;;:47;;:38;;:21;:38::i;:47::-;:76;;97081:107;;;;-1:-1:-1;;;97081:107:0;;;;;;;:::i;:::-;97212:39;;:::i;:::-;97254:38;97269:4;97275:16;97254:14;:38::i;:::-;97212:80;;97609:31;:22;:29;:31::i;:::-;:36;97605:427;;97674:14;97666:4;:22;;;;;;;;;97662:359;;;97772:31;:22;:29;:31::i;:::-;97743:25;:16;:23;:25::i;:::-;:60;;97735:102;;;;-1:-1:-1;;;97735:102:0;;;;;;;:::i;:::-;97662:359;;;97940:31;:22;:29;:31::i;:::-;97911:25;:16;:23;:25::i;:::-;:60;;97903:102;;;;-1:-1:-1;;;97903:102:0;;;;;;;:::i;:::-;98179:21;98174:146;;98241:67;98267:4;98273:16;98291;98241:25;:67::i;:::-;98217:91;;98174:146;98332:198;98368:14;98360:4;:22;;;;;;;;;:61;;98407:14;98360:61;;;98385:19;98360:61;98436:16;98467;98498:21;98332:13;:198::i;:::-;98548:70;98559:4;98565:25;:16;:23;:25::i;:::-;98592;:16;:23;:25::i;:::-;98548:70;;;;;;;;:::i;:::-;;;;;;;;98636:16;96601:2059;-1:-1:-1;;;;;96601:2059:0:o;29699:173::-;29772:14;;:::i;:::-;29799:16;;:::i;:::-;29841:3;;29832;;:13;;:8;:13::i;63623:329::-;63741:34;;:::i;:::-;63816:1;-1:-1:-1;;;;;63801:16:0;;63819:21;;;;;;;;;;;;;;;;;63793:48;;;;;-1:-1:-1;;;63793:48:0;;;;;;;;:::i;:::-;;63852:36;;:::i;:::-;63903:22;:1;63922;63903:11;:22::i;36872:185::-;36948:20;;:::i;:::-;36981:22;;:::i;:::-;37020:3;;:10;;37028:1;37020:7;:10::i;95543:308::-;95722:39;:16;95744;95722:21;:39::i;:::-;95708:53;:11;:53;;;95796:17;;;;;;;;;;;;95777:66;;95796:19;;:17;:19::i;:::-;95817:25;:16;:23;:25::i;:::-;95777:66;;;;;;;:::i;:::-;;;;;;;;95543:308;;:::o;63245:304::-;63397:34;;:::i;:::-;63376:1;61931;:3;;;-1:-1:-1;;;;;61916:18:0;;61936:21;;;;;;;;;;;;;;;;;61908:50;;;;;-1:-1:-1;;;61908:50:0;;;;;;;;:::i;:::-;;63449:36:::1;;:::i;:::-;63500:22;63507:14;63519:1;63507:11;:14::i;:::-;63500:1:::0;;:6:::1;:22::i;65663:385::-:0;65711:7;65739:1;65735;:5;65731:310;;;65769:1;65805;65801;65797:5;;:9;65821:92;65832:1;65828;:5;65821:92;;;65858:1;65854:5;;65896:1;65891;65887;65883;:5;;;;;;:9;65882:15;;;;;;65878:19;;65821:92;;;-1:-1:-1;65934:1:0;-1:-1:-1;65927:8:0;;65731:310;65957:6;;65953:88;;-1:-1:-1;65987:1:0;65980:8;;65953:88;-1:-1:-1;66028:1:0;66021:8;;62448:304;62600:34;;:::i;:::-;62579:1;61931;:3;;;-1:-1:-1;;;;;61916:18:0;;61936:21;;;;;;;;;;;;;;;;;61908:50;;;;;-1:-1:-1;;;61908:50:0;;;;;;;;:::i;:::-;;62652:36:::1;;:::i;:::-;62720:3:::0;;62705;;:20:::1;::::0;:7:::1;:20::i;95859:734::-:0;95909:20;95932:14;:12;:14::i;:::-;95998:16;96015:23;;95909:37;;-1:-1:-1;95957:38:0;;-1:-1:-1;;96015:27:0;;;95998:45;;;;;;;;;;;;;;;;95957:86;;96133:14;:26;;;96117:12;:42;96113:365;;;96211:17;96176:52;;;96277:16;96243:50;:31;;;:50;96113:365;;;96366:85;;;;;;;;96382:17;96366:85;;;;;;;;;;;;;;;;;96401:16;96366:85;;;;;;96326:16;;-1:-1:-1;;96419:17:0;:15;:17::i;:::-;96366:85;;;;;;;;;96326:140;;;;;;;;-1:-1:-1;96326:140:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96113:365;96512:24;;;;;;;;;:17;:24;;;96493:92;;96512:26;;:24;:26::i;:::-;96540:23;;;;;;;;;:16;:23;;;:25;;:23;:25::i;:::-;96567:17;:15;:17::i;:::-;96493:92;;;;;;;;:::i;100378:312::-;100453:22;;:::i;:::-;100488:33;;:::i;:::-;100545:28;100532:41;;100607:16;:23;:30;;100635:1;100607:27;:30::i;:::-;100584:20;;;:53;100655:27;100584:6;100672:9;100655:8;:27::i;36618:197::-;36703:20;;:::i;:::-;36736:22;;:::i;:::-;36784:3;;36775;;:13;;:8;:13::i;4759:192::-;4845:7;4881:12;4873:6;;;;4865:29;;;;-1:-1:-1;;;4865:29:0;;;;;;;;:::i;:::-;-1:-1:-1;;;4917:5:0;;;4759:192::o;30672:568::-;30728:6;30972;30968:47;;-1:-1:-1;31002:1:0;30995:8;;30968:47;31037:1;-1:-1:-1;;31037:7:0;:27;;;;;-1:-1:-1;;;31048:1:0;:16;31037:27;31035:30;31027:82;;;;-1:-1:-1;;;31027:82:0;;;;;;;:::i;:::-;31133:5;;;31137:1;31133;:5;:1;31157:5;;;;;:10;31149:62;;;;-1:-1:-1;;;31149:62:0;;;;;;;:::i;32236:218::-;32292:6;32322:5;;;32347:6;;;;;;:16;;;32362:1;32357;:6;;32347:16;32346:38;;;;32373:1;32369;:5;:14;;;;;32382:1;32378;:5;32369:14;32338:87;;;;-1:-1:-1;;;32338:87:0;;;;;;;:::i;32699:215::-;32755:6;32785:5;;;32810:6;;;;;;:16;;;32825:1;32820;:6;;32810:16;32809:38;;;;32836:1;32832;:5;:14;;;;;32845:1;32841;:5;32832:14;32801:84;;;;-1:-1:-1;;;32801:84:0;;;;;;;:::i;100698:2406::-;100821:22;;:::i;:::-;100861:35;;:::i;:::-;100899:37;100928:7;100899:28;:37::i;:::-;100861:75;-1:-1:-1;100951:14:0;100947:66;;100989:12;-1:-1:-1;100982:19:0;;100947:66;101025:21;101049:32;101071:9;101049:17;:15;:17::i;:::-;:21;;:32::i;:::-;101025:56;;101092:38;;:::i;:::-;101133:16;101150:7;:21;;;101133:39;;;;;;;;;;;;;;;;;101092:80;;;;;;;;101133:39;;;;;;;101092:80;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;101092:80:0;;;;;;;;;;;101337:16;:23;101092:80;;-1:-1:-1;101337:28:0;;:74;;;101398:13;101369:15;:25;;;:42;;101337:74;101333:126;;;101435:12;101428:19;;;;;;;101333:126;101499:25;;;;101471;101552:40;101499:25;101552:17;:15;:17::i;:40::-;101535:57;;101603:36;;:::i;:::-;101642:30;:12;101665:6;101642:22;:30::i;:::-;101603:69;;101683:1362;101764:21;;;;101760:105;;101818:31;:13;101842:6;101818:23;:31::i;:::-;101811:38;;;;;;;;;;101760:105;101905:21;;;;:28;;101931:1;101905:25;:28::i;:::-;101881:21;;;:52;;;101966:16;:39;;:16;;101881:52;101966:39;;;;;;;;;;;;;;;101948:57;;;;;;;;101966:39;;;;;;;101948:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;101948:57:0;;;;;;;;;;;-1:-1:-1;102035:37:0;102064:7;102035:28;:37::i;:::-;102020:52;;102204:13;102175:15;:25;;;:42;102171:580;;102631:80;102650:60;102673:36;:17;102695:13;102673:21;:36::i;:::-;102650:12;;:22;:60::i;:::-;102631:13;;:18;:80::i;:::-;102615:96;;102730:5;;102171:580;102767:20;102790:48;102812:15;:25;;;102790:17;:21;;:48;;;;:::i;:::-;102767:71;-1:-1:-1;102869:56:0;102888:36;:12;102767:71;102888:22;:36::i;:::-;102869:13;;:18;:56::i;:::-;102853:72;-1:-1:-1;102949:24:0;:6;102960:12;102949:10;:24::i;:::-;102940:33;;103008:15;:25;;;102988:45;;101683:1362;;;;103062:34;:13;103086:9;103062:23;:34::i;:::-;103055:41;100698:2406;-1:-1:-1;;;;;;;;;100698:2406:0:o;26401:109::-;26485:17;;26481:2;:21;;26401:109::o;106955:668::-;107156:4;107173:32;;:::i;:::-;107241:26;;;;107208:27;;:60;;:32;:60::i;:::-;107173:95;;107279:33;;:::i;:::-;107315:58;107330:42;107349:22;107330:13;:11;:13::i;:::-;:18;;:42::i;107315:58::-;107279:94;;107384:33;;:::i;:::-;107420:58;107435:42;107454:22;107435:13;:11;:13::i;:::-;:18;;:42::i;107420:58::-;107384:94;-1:-1:-1;107521:1:0;107495:22;:6;107506:10;107495;:22::i;:::-;:27;;;;:58;;;;-1:-1:-1;107552:1:0;107526:22;:6;107537:10;107526;:22::i;:::-;:27;;;;107495:58;107491:103;;;107577:5;107570:12;;;;;;;107491:103;-1:-1:-1;107611:4:0;;106955:668;-1:-1:-1;;;;;;106955:668:0:o;26991:108::-;27050:7;27077:14;27082:1;27085;27088:2;27077:4;:14::i;6785:278::-;6871:7;6906:12;6899:5;6891:28;;;;-1:-1:-1;;;6891:28:0;;;;;;;;:::i;:::-;;6930:9;6946:1;6942;:5;;;;;;;6785:278;-1:-1:-1;;;;;6785:278:0:o;28830:172::-;28903:14;;:::i;:::-;28930:16;;:::i;:::-;28971:3;;28963;;:12;;:7;:12::i;29046:172::-;29119:14;;:::i;:::-;29146:16;;:::i;:::-;29187:3;;29179;;:12;;:7;:12::i;22672:65::-;20809:13;;;;;;;;:33;;;20826:16;:14;:16::i;:::-;20809:50;;;-1:-1:-1;20847:12:0;;;;20846:13;20809:50;20801:109;;;;-1:-1:-1;;;20801:109:0;;;;;;;:::i;:::-;20923:19;20946:13;;;;;;20945:14;20970:101;;;;21005:13;:20;;-1:-1:-1;;;;21005:20:0;;;;;21040:19;21021:4;21040:19;;;21101:14;21097:68;;;21148:5;21132:21;;-1:-1:-1;;21132:21:0;;;22672:65;:::o;24193:196::-;20809:13;;;;;;;;:33;;;20826:16;:14;:16::i;:::-;20809:50;;;-1:-1:-1;20847:12:0;;;;20846:13;20809:50;20801:109;;;;-1:-1:-1;;;20801:109:0;;;;;;;:::i;:::-;20923:19;20946:13;;;;;;20945:14;20970:101;;;;21005:13;:20;;-1:-1:-1;;;;21005:20:0;;;;;21040:19;21021:4;21040:19;;;20970:101;24261:17:::1;24281:12;:10;:12::i;:::-;24304:6;:18:::0;;-1:-1:-1;;;;;;24304:18:0::1;-1:-1:-1::0;;;;;24304:18:0;::::1;::::0;;::::1;::::0;;;24338:43:::1;::::0;24304:18;;-1:-1:-1;24304:18:0;-1:-1:-1;;24338:43:0::1;::::0;-1:-1:-1;;24338:43:0::1;21083:1;21101:14:::0;21097:68;;;21148:5;21132:21;;-1:-1:-1;;21132:21:0;;;24193:196;:::o;104657:729::-;104842:4;104859:47;;:::i;:::-;104931:14;104923:4;:22;;;;;;;;;104922:238;;105120:21;;;;;;;;;:16;:21;;;105073:87;;105120:39;;105142:16;105120:21;:39::i;:::-;105073:22;;;;;;;;;:17;:22;;;:41;;105096:17;105073:22;:41::i;:87::-;104922:238;;;105013:21;;;;;;;;;:16;:21;;;104966:87;;105013:39;;105035:16;105013:21;:39::i;:::-;104966:22;;;;;;;;;:17;:22;;;:41;;104989:17;104966:22;:41::i;:87::-;105191:187;;;;;;;;;105275:21;105191:187;;;105315:16;105332:23;;104859:301;;-1:-1:-1;105191:187:0;;104859:301;;105191:187;105315:16;105332:30;;105360:1;105332:27;:30::i;:::-;105315:48;;;;;;;;;;;;;;;;;105191:187;;;;;;;;105315:48;;;;;;;105191:187;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;105191:187:0;;;;;;;;;;:22;:187::i;27466:108::-;27525:7;27552:14;27557:1;27560;27563:2;27552:4;:14::i;31714:271::-;31770:6;31797;31789:51;;;;-1:-1:-1;;;31789:51:0;;;;;;;:::i;:::-;31861:1;-1:-1:-1;;31861:7:0;:27;;;;;-1:-1:-1;;;31872:1:0;:16;31861:27;31859:30;31851:76;;;;-1:-1:-1;;;31851:76:0;;;;;;;:::i;:::-;31940:8;31955:1;31951;:5;;;;;;;31714:271;-1:-1:-1;;;;31714:271:0:o;36135:197::-;36220:20;;:::i;:::-;36253:22;;:::i;:::-;36301:3;;36292;;:13;;:8;:13::i;34316:105::-;34373:6;34399:14;34404:1;34407;34410:2;34399:4;:14::i;103112:1537::-;103252:22;;:::i;:::-;103292:31;;:::i;:::-;103326:16;103343:6;:20;;;103326:38;;;;;;;;;;;;;;;;103292:72;;;;;;;;103326:38;;;;;;;103292:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;103292:72:0;;;;;;;;;-1:-1:-1;103541:10:0;;:42;;;;;;;;;103537:1064;;;103639:25;;;;103607:26;;:58;;:31;:58::i;:::-;103600:65;;;;;103537:1064;103701:26;103687:10;;:40;;;;;;;;;103683:918;;;103748:33;:6;:12;;;:24;;;:31;:33::i;:::-;103744:100;;103814:14;:12;:14::i;103744:100::-;103886:22;103862:6;:12;;;:20;;;:46;;;;;;;;;103858:732;;;104009:12;;;;:16;;104052:24;;;;;104103:26;;104156:25;;;;103957:247;;104103:26;103957:25;:247::i;103858:732::-;104254:23;104230:6;:12;;;:20;;;:47;;;;;;;;;104226:364;;;104379:12;;;;:16;;104422:24;;;;;104473:26;;104526:25;;;;104326:248;;104473:26;104326;:248::i;104226:364::-;104611:30;;-1:-1:-1;;;104611:30:0;;;;;;;:::i;29489:168::-;29560:14;;:::i;:::-;29587:16;;:::i;:::-;29620:3;;:10;;29628:1;29620:7;:10::i;29924:168::-;29995:14;;:::i;:::-;30022:16;;:::i;:::-;30055:3;;:10;;30063:1;30055:7;:10::i;27200:172::-;27309:7;27336:28;27349:14;27354:8;27349:4;:14::i;:::-;27336:8;:1;27342;27336:5;:8::i;27676:172::-;27785:7;27812:28;27838:1;27812:21;27818:14;27823:8;27818:4;:14::i;:::-;27812:1;;:5;:21::i;33847:105::-;33904:6;33930:14;33935:1;33938;33941:2;33930:4;:14::i;34523:169::-;34630:6;34656:28;34682:1;34656:21;34662:14;34667:8;34662:4;:14::i;:::-;34656:1;;:5;:21::i;:::-;:25;;:28::i;34053:169::-;34160:6;34186:28;34199:14;34204:8;34199:4;:14::i;:::-;34186:8;:1;34192;34186:5;:8::i;-1:-1:-1:-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;1735:158;;1846:2;1837:6;1832:3;1828:16;1824:25;1821:2;;;-1:-1;;1852:12;1821:2;-1:-1;1872:15;1814:79;-1:-1;1814:79::o;1929:320::-;;2043:4;2031:9;2026:3;2022:19;2018:30;2015:2;;;-1:-1;;2051:12;2015:2;2079:20;2043:4;2079:20;:::i;:::-;3469;;2153:75;;-1:-1;2070:29;2009:240;-1:-1;2009:240::o;3680:241::-;;3784:2;3772:9;3763:7;3759:23;3755:32;3752:2;;;-1:-1;;3790:12;3752:2;85:6;72:20;97:33;124:5;97:33;:::i;3928:235::-;;4029:2;4017:9;4008:7;4004:23;4000:32;3997:2;;;-1:-1;;4035:12;3997:2;219:6;206:20;60508:5;56418:13;56411:21;60486:5;60483:32;60473:2;;-1:-1;;60519:12;4170:615;;;;4370:2;4358:9;4349:7;4345:23;4341:32;4338:2;;;-1:-1;;4376:12;4338:2;1210:6;1197:20;1222:41;1257:5;1222:41;:::i;:::-;4428:71;-1:-1;4554:80;4626:7;4536:2;4602:22;;4554:80;:::i;:::-;4544:90;;4689:80;4761:7;4671:2;4741:9;4737:22;4689:80;:::i;:::-;4679:90;;4332:453;;;;;:::o;4792:735::-;;;;;5006:3;4994:9;4985:7;4981:23;4977:33;4974:2;;;-1:-1;;5013:12;4974:2;1210:6;1197:20;1222:41;1257:5;1222:41;:::i;:::-;5065:71;-1:-1;5191:80;5263:7;5173:2;5239:22;;5191:80;:::i;:::-;5181:90;;5326:80;5398:7;5308:2;5378:9;5374:22;5326:80;:::i;:::-;5316:90;;5443:2;5483:9;5479:22;206:20;60508:5;56418:13;56411:21;60486:5;60483:32;60473:2;;-1:-1;;60519:12;60473:2;4968:559;;;;-1:-1;4968:559;;-1:-1;;4968:559::o;5534:432::-;;;5688:2;5676:9;5667:7;5663:23;5659:32;5656:2;;;-1:-1;;5694:12;5656:2;1210:6;1197:20;1222:41;1257:5;1222:41;:::i;:::-;5746:71;-1:-1;5872:78;5942:7;5854:2;5918:22;;5872:78;:::i;:::-;5862:88;;5650:316;;;;;:::o;5973:783::-;;;;;6211:3;6199:9;6190:7;6186:23;6182:33;6179:2;;;-1:-1;;6218:12;6179:2;1210:6;1197:20;1222:41;1257:5;1222:41;:::i;:::-;6270:71;-1:-1;6396:78;6466:7;6378:2;6442:22;;6396:78;:::i;:::-;6386:88;;6529:78;6599:7;6511:2;6579:9;6575:22;6529:78;:::i;:::-;6519:88;;6662:78;6732:7;6644:2;6712:9;6708:22;6662:78;:::i;:::-;6652:88;;6173:583;;;;;;;:::o;6763:509::-;;;;6910:2;6898:9;6889:7;6885:23;6881:32;6878:2;;;-1:-1;;6916:12;6878:2;1210:6;1197:20;1222:41;1257:5;1222:41;:::i;:::-;6968:72;-1:-1;7077:2;7116:22;;72:20;97:33;72:20;97:33;:::i;:::-;6872:400;;7085:63;;-1:-1;;;7185:2;7224:22;;;;3469:20;;6872:400::o;7279:295::-;;7410:2;7398:9;7389:7;7385:23;7381:32;7378:2;;;-1:-1;;7416:12;7378:2;7478:80;7550:7;7526:22;7478:80;:::i;7581:474::-;;;7756:2;7744:9;7735:7;7731:23;7727:32;7724:2;;;-1:-1;;7762:12;7724:2;7824:80;7896:7;7872:22;7824:80;:::i;:::-;7814:90;;7959:80;8031:7;7941:2;8011:9;8007:22;7959:80;:::i;8062:291::-;;8191:2;8179:9;8170:7;8166:23;8162:32;8159:2;;;-1:-1;;8197:12;8159:2;8259:78;8329:7;8305:22;8259:78;:::i;8360:313::-;;8500:2;8488:9;8479:7;8475:23;8471:32;8468:2;;;-1:-1;;8506:12;8468:2;2446:20;8500:2;2446:20;:::i;:::-;3617:13;;2520:86;;-1:-1;2527:16;8462:211;-1:-1;8462:211::o;8680:466::-;;;8851:2;8839:9;8830:7;8826:23;8822:32;8819:2;;;-1:-1;;8857:12;8819:2;8919:78;8989:7;8965:22;8919:78;:::i;9485:653::-;;;;9704:2;9692:9;9683:7;9679:23;9675:32;9672:2;;;-1:-1;;9710:12;9672:2;9772:84;9848:7;9824:22;9772:84;:::i;:::-;9762:94;;9911:78;9981:7;9893:2;9961:9;9957:22;9911:78;:::i;:::-;9901:88;;10044:78;10114:7;10026:2;10094:9;10090:22;10044:78;:::i;10642:241::-;;10746:2;10734:9;10725:7;10721:23;10717:32;10714:2;;;-1:-1;;10752:12;10714:2;-1:-1;3469:20;;10708:175;-1:-1;10708:175::o;10890:263::-;;11005:2;10993:9;10984:7;10980:23;10976:32;10973:2;;;-1:-1;;11011:12;10973:2;-1:-1;3617:13;;10967:186;-1:-1;10967:186::o;11160:366::-;;;11281:2;11269:9;11260:7;11256:23;11252:32;11249:2;;;-1:-1;;11287:12;11249:2;-1:-1;;3469:20;;;11439:2;11478:22;;;340:20;;-1:-1;11243:283::o;11533:1793::-;;;;;;;;;;;;;11908:3;11896:9;11887:7;11883:23;11879:33;11876:2;;;-1:-1;;11915:12;11876:2;3482:6;3469:20;11967:63;;12067:2;12110:9;12106:22;3469:20;12075:63;;12175:2;12218:9;12214:22;3469:20;12183:63;;12283:2;12326:9;12322:22;3469:20;12291:63;;12391:3;12453:9;12449:22;72:20;97:33;124:5;97:33;:::i;:::-;12400:81;-1:-1;12518:3;12576:22;;72:20;97:33;72:20;97:33;:::i;:::-;12527:81;-1:-1;12645:3;12708:22;;72:20;97:33;72:20;97:33;:::i;:::-;12654:86;-1:-1;12777:3;12817:22;;340:20;;-1:-1;12886:3;12926:22;;72:20;97:33;72:20;97:33;:::i;:::-;12895:63;-1:-1;12995:3;13035:22;;3469:20;;-1:-1;13104:3;13145:22;;3469:20;;-1:-1;13214:3;13278:22;;72:20;97:33;72:20;97:33;:::i;:::-;13223:87;;;;11870:1456;;;;;;;;;;;;;;:::o;30614:222::-;-1:-1;;;;;57397:54;;;;13404:37;;30741:2;30726:18;;30712:124::o;30843:476::-;-1:-1;;;;;57397:54;;13404:37;;31042:2;31027:18;;57073:41;57108:5;57073:41;:::i;:::-;31213:2;31198:18;;14784:57;;;;31305:2;31290:18;15157:59;31013:306;;-1:-1;31013:306::o;31809:353::-;-1:-1;;;;;57397:54;;;;13404:37;;32148:2;32133:18;;15157:59;31974:2;31959:18;;31945:217::o;32169:210::-;56418:13;;56411:21;13518:34;;32290:2;32275:18;;32261:118::o;32386:222::-;13635:37;;;32513:2;32498:18;;32484:124::o;32615:333::-;13635:37;;;32934:2;32919:18;;13635:37;32770:2;32755:18;;32741:207::o;34312:868::-;34679:3;34664:19;;57073:41;57108:5;57073:41;:::i;:::-;14638:56;;;29063:23;;34900:2;34885:18;;13635:37;29063:23;;35033:2;35018:18;;13635:37;29063:23;35166:2;35151:18;;;13635:37;34650:530;:::o;35187:456::-;35376:2;35361:18;;57073:41;57108:5;57073:41;:::i;:::-;14638:56;;;35546:2;35531:18;;13635:37;;;;35629:2;35614:18;;;13635:37;35347:296;:::o;35650:458::-;35840:2;35825:18;;57073:41;57108:5;57073:41;:::i;:::-;14784:57;;;-1:-1;;;;;57397:54;;;;36011:2;35996:18;;13404:37;36094:2;36079:18;;;13635:37;35811:297;:::o;36676:310::-;;36823:2;;36844:17;36837:47;15677:5;55913:12;56070:6;36823:2;36812:9;36808:18;56058:19;-1:-1;59781:101;59795:6;59792:1;59789:13;59781:101;;;59862:11;;;;;59856:18;59843:11;;;56098:14;59843:11;59836:39;59810:10;;59781:101;;;59897:6;59894:1;59891:13;59888:2;;;-1:-1;56098:14;59953:6;36812:9;59944:16;;59937:27;59888:2;-1:-1;60069:7;60053:14;-1:-1;;60049:28;15835:39;;;;56098:14;15835:39;;36794:192;-1:-1;;;36794:192::o;36993:416::-;37193:2;37207:47;;;16111:2;37178:18;;;56058:19;-1:-1;;;56098:14;;;16127:44;16190:12;;;37164:245::o;37416:416::-;37616:2;37630:47;;;16441:2;37601:18;;;56058:19;-1:-1;;;56098:14;;;16457:39;16515:12;;;37587:245::o;37839:416::-;38039:2;38053:47;;;16766:2;38024:18;;;56058:19;-1:-1;;;56098:14;;;16782:43;16844:12;;;38010:245::o;38262:416::-;38462:2;38476:47;;;17095:2;38447:18;;;56058:19;17131:34;56098:14;;;17111:55;-1:-1;;;17186:12;;;17179:30;17228:12;;;38433:245::o;38685:416::-;38885:2;38899:47;;;17479:2;38870:18;;;56058:19;17515:29;56098:14;;;17495:50;17564:12;;;38856:245::o;39108:416::-;39308:2;39322:47;;;17815:2;39293:18;;;56058:19;17851:27;56098:14;;;17831:48;17898:12;;;39279:245::o;39531:416::-;39731:2;39745:47;;;18149:2;39716:18;;;56058:19;18185:28;56098:14;;;18165:49;18233:12;;;39702:245::o;39954:416::-;40154:2;40168:47;;;18484:2;40139:18;;;56058:19;18520:34;56098:14;;;18500:55;-1:-1;;;18575:12;;;18568:25;18612:12;;;40125:245::o;40377:416::-;40577:2;40591:47;;;18863:2;40562:18;;;56058:19;-1:-1;;;56098:14;;;18879:41;18939:12;;;40548:245::o;40800:416::-;41000:2;41014:47;;;19190:2;40985:18;;;56058:19;19226:30;56098:14;;;19206:51;19276:12;;;40971:245::o;41223:416::-;41423:2;41437:47;;;19527:2;41408:18;;;56058:19;-1:-1;;;56098:14;;;19543:38;19600:12;;;41394:245::o;41646:416::-;41846:2;41860:47;;;19851:2;41831:18;;;56058:19;-1:-1;;;56098:14;;;19867:44;19930:12;;;41817:245::o;42069:416::-;42269:2;42283:47;;;20181:2;42254:18;;;56058:19;-1:-1;;;56098:14;;;20197:38;20254:12;;;42240:245::o;42492:416::-;42692:2;42706:47;;;20505:2;42677:18;;;56058:19;20541:28;56098:14;;;20521:49;20589:12;;;42663:245::o;42915:416::-;43115:2;43129:47;;;20840:2;43100:18;;;56058:19;20876:33;56098:14;;;20856:54;20929:12;;;43086:245::o;43338:416::-;43538:2;43552:47;;;21180:2;43523:18;;;56058:19;21216:34;56098:14;;;21196:55;-1:-1;;;21271:12;;;21264:38;21321:12;;;43509:245::o;43761:416::-;43961:2;43975:47;;;21572:2;43946:18;;;56058:19;21608:34;56098:14;;;21588:55;-1:-1;;;21663:12;;;21656:25;21700:12;;;43932:245::o;44184:416::-;44384:2;44398:47;;;21951:2;44369:18;;;56058:19;-1:-1;;;56098:14;;;21967:43;22029:12;;;44355:245::o;44607:416::-;44807:2;44821:47;;;22280:2;44792:18;;;56058:19;22316:31;56098:14;;;22296:52;22367:12;;;44778:245::o;45030:416::-;45230:2;45244:47;;;22618:2;45215:18;;;56058:19;22654:34;56098:14;;;22634:55;-1:-1;;;22709:12;;;22702:25;22746:12;;;45201:245::o;45453:416::-;45653:2;45667:47;;;22997:2;45638:18;;;56058:19;23033:30;56098:14;;;23013:51;23083:12;;;45624:245::o;45876:416::-;46076:2;46090:47;;;46061:18;;;56058:19;23370:34;56098:14;;;23350:55;23424:12;;;46047:245::o;46299:416::-;46499:2;46513:47;;;23675:2;46484:18;;;56058:19;23711:34;56098:14;;;23691:55;-1:-1;;;23766:12;;;23759:31;23809:12;;;46470:245::o;46722:416::-;46922:2;46936:47;;;24060:2;46907:18;;;56058:19;-1:-1;;;56098:14;;;24076:36;24131:12;;;46893:245::o;47145:416::-;47345:2;47359:47;;;24382:2;47330:18;;;56058:19;-1:-1;;;56098:14;;;24398:42;24459:12;;;47316:245::o;47568:416::-;47768:2;47782:47;;;24710:2;47753:18;;;56058:19;24746:31;56098:14;;;24726:52;24797:12;;;47739:245::o;47991:416::-;48191:2;48205:47;;;25048:2;48176:18;;;56058:19;25084:30;56098:14;;;25064:51;25134:12;;;48162:245::o;48414:416::-;48614:2;48628:47;;;25385:2;48599:18;;;56058:19;25421:26;56098:14;;;25401:47;25467:12;;;48585:245::o;48837:416::-;49037:2;49051:47;;;25718:2;49022:18;;;56058:19;-1:-1;;;56098:14;;;25734:45;25798:12;;;49008:245::o;49260:416::-;49460:2;49474:47;;;26049:2;49445:18;;;56058:19;-1:-1;;;56098:14;;;26065:36;26120:12;;;49431:245::o;49683:416::-;49883:2;49897:47;;;26371:2;49868:18;;;56058:19;26407:34;56098:14;;;26387:55;-1:-1;;;26462:12;;;26455:28;26502:12;;;49854:245::o;50106:416::-;50306:2;50320:47;;;26753:2;50291:18;;;56058:19;-1:-1;;;56098:14;;;26769:43;26831:12;;;50277:245::o;50529:416::-;50729:2;50743:47;;;50714:18;;;56058:19;27118:34;56098:14;;;27098:55;27172:12;;;50700:245::o;50952:391::-;27558:23;;29063;13635:37;;27804:4;27793:16;;;27787:23;29063;27914:14;;;13635:37;28020:4;28009:16;;;28003:23;29063;28130:14;;;13635:37;28237:4;28226:16;;;28220:23;29063;28359:14;;;13635:37;;;;51163:3;51148:19;;51134:209::o;51350:326::-;3469:20;;13635:37;;51529:2;51514:18;;51500:176::o;51683:322::-;29063:23;;13635:37;;51860:2;51845:18;;51831:174::o;52012:533::-;29063:23;;13635:37;;29063:23;52531:2;52516:18;;13635:37;52267:2;52252:18;;52238:307::o;52552:756::-;29063:23;;13635:37;;29063:23;;53128:2;53113:18;;13635:37;53211:2;53196:18;;13635:37;53294:2;53279:18;;13635:37;52863:3;52848:19;;52834:474::o;53897:440::-;13635:37;;;54242:2;54227:18;;13635:37;;;;54323:2;54308:18;;13635:37;54078:2;54063:18;;54049:288::o;54795:760::-;13635:37;;;55217:2;55202:18;;13635:37;;;;55300:2;55285:18;;13635:37;;;;55381:2;55366:18;;13635:37;55462:3;55447:19;;13635:37;56418:13;56411:21;55540:3;55525:19;;13518:34;55052:3;55037:19;;55023:532::o;55562:256::-;55624:2;55618:9;55650:17;;;55725:18;55710:34;;55746:22;;;55707:62;55704:2;;;55782:1;;55772:12;55704:2;55624;55791:22;55602:216;;-1:-1;55602:216::o;60090:99::-;60167:1;60160:5;60157:12;60147:2;;60173:9;60303:117;-1:-1;;;;;57397:54;;60362:35;;60352:2;;60411:1;;60401:12;61329:102;61406:1;61399:5;61396:12;61386:2;;61422:1;;61412:12

Swarm Source

ipfs://3ee68a2d022332a70ef29134324f5224abcecd69beaf731aaf57e5a1b6f7a140
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading