ETH Price: $3,271.24 (+5.15%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
142971172022-02-28 21:39:151066 days ago1646084355
0x07C89CC8...A9D920Ac0
0 ETH
142970422022-02-28 21:20:401066 days ago1646083240
0x07C89CC8...A9D920Ac0
0 ETH
142952152022-02-28 14:38:291067 days ago1646059109
0x07C89CC8...A9D920Ac0
0 ETH
142939812022-02-28 10:06:261067 days ago1646042786
0x07C89CC8...A9D920Ac0
0 ETH
142913562022-02-28 0:05:291067 days ago1646006729
0x07C89CC8...A9D920Ac0
0 ETH
142912052022-02-27 23:27:111067 days ago1646004431
0x07C89CC8...A9D920Ac0
0 ETH
142909722022-02-27 22:37:221067 days ago1646001442
0x07C89CC8...A9D920Ac0
0 ETH
142909632022-02-27 22:35:361067 days ago1646001336
0x07C89CC8...A9D920Ac0
0 ETH
142909562022-02-27 22:34:061067 days ago1646001246
0x07C89CC8...A9D920Ac0
0 ETH
142909482022-02-27 22:32:091067 days ago1646001129
0x07C89CC8...A9D920Ac0
0 ETH
142909262022-02-27 22:26:141067 days ago1646000774
0x07C89CC8...A9D920Ac0
0 ETH
142900892022-02-27 19:21:271067 days ago1645989687
0x07C89CC8...A9D920Ac0
0 ETH
142735972022-02-25 6:10:481070 days ago1645769448
0x07C89CC8...A9D920Ac0
0 ETH
142699972022-02-24 16:58:101071 days ago1645721890
0x07C89CC8...A9D920Ac0
0 ETH
142690852022-02-24 13:33:201071 days ago1645709600
0x07C89CC8...A9D920Ac0
0 ETH
142690832022-02-24 13:32:501071 days ago1645709570
0x07C89CC8...A9D920Ac0
0 ETH
142690832022-02-24 13:32:501071 days ago1645709570
0x07C89CC8...A9D920Ac0
0 ETH
142690832022-02-24 13:32:501071 days ago1645709570
0x07C89CC8...A9D920Ac0
0 ETH
142690802022-02-24 13:32:251071 days ago1645709545
0x07C89CC8...A9D920Ac0
0 ETH
142690802022-02-24 13:32:251071 days ago1645709545
0x07C89CC8...A9D920Ac0
0 ETH
142690802022-02-24 13:32:251071 days ago1645709545
0x07C89CC8...A9D920Ac0
0 ETH
142690802022-02-24 13:32:251071 days ago1645709545
0x07C89CC8...A9D920Ac0
0 ETH
142690802022-02-24 13:32:251071 days ago1645709545
0x07C89CC8...A9D920Ac0
0 ETH
142685142022-02-24 11:26:481071 days ago1645702008
0x07C89CC8...A9D920Ac0
0 ETH
142683152022-02-24 10:41:231071 days ago1645699283
0x07C89CC8...A9D920Ac0
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PerpetualManagerFront

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 283 runs

Other Settings:
default evmVersion, GNU GPLv3 license

Contract Source Code (Solidity)

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

// Sources flattened with hardhat v2.6.7 https://hardhat.org

// File @openzeppelin/contracts-upgradeable/proxy/utils/[email protected]

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^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 {ERC1967Proxy-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 || !_initialized, "Initializable: contract is already initialized");

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

        _;

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


// File @openzeppelin/contracts-upgradeable/utils/[email protected]



pragma solidity ^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 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) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
    uint256[50] private __gap;
}


// File @openzeppelin/contracts-upgradeable/security/[email protected]



pragma solidity ^0.8.0;


/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

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

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal initializer {
        __Context_init_unchained();
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal initializer {
        _paused = false;
    }

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

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

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

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
    uint256[49] private __gap;
}


// File @openzeppelin/contracts-upgradeable/token/ERC721/[email protected]



pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721ReceiverUpgradeable {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}


// File @openzeppelin/contracts-upgradeable/utils/introspection/[email protected]



pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}


// File @openzeppelin/contracts-upgradeable/token/ERC721/[email protected]



pragma solidity ^0.8.0;

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721Upgradeable is IERC165Upgradeable {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}


// File @openzeppelin/contracts-upgradeable/utils/introspection/[email protected]



pragma solidity ^0.8.0;


/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal initializer {
        __ERC165_init_unchained();
    }

    function __ERC165_init_unchained() internal initializer {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }
    uint256[50] private __gap;
}


// File @openzeppelin/contracts-upgradeable/utils/[email protected]



pragma solidity ^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;
        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");

        (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");

        (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");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}


// File @openzeppelin/contracts-upgradeable/utils/[email protected]



pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library CountersUpgradeable {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}


// File @openzeppelin/contracts/token/ERC20/[email protected]



pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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


// File @openzeppelin/contracts/token/ERC20/extensions/[email protected]



pragma solidity ^0.8.0;

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}


// File @openzeppelin/contracts/utils/[email protected]



pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        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");

        (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");

        (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");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

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

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}


// File @openzeppelin/contracts/token/ERC20/utils/[email protected]



pragma solidity ^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 SafeERC20 {
    using Address for address;

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

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

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

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

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

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

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


// File @openzeppelin/contracts-upgradeable/utils/[email protected]



pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library StringsUpgradeable {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}


// File contracts/interfaces/IAccessControl.sol



pragma solidity ^0.8.7;

/// @title IAccessControl
/// @author Forked from OpenZeppelin
/// @notice Interface for `AccessControl` contracts
interface IAccessControl {
    function hasRole(bytes32 role, address account) external view returns (bool);

    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    function grantRole(bytes32 role, address account) external;

    function revokeRole(bytes32 role, address account) external;

    function renounceRole(bytes32 role, address account) external;
}


// File contracts/external/AccessControlUpgradeable.sol



pragma solidity ^0.8.7;


/**
 * @dev This contract is fully forked from OpenZeppelin `AccessControlUpgradeable`.
 * The only difference is the removal of the ERC165 implementation as it's not
 * needed in Angle.
 *
 * Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControlUpgradeable is Initializable, IAccessControl {
    function __AccessControl_init() internal initializer {
        __AccessControl_init_unchained();
    }

    function __AccessControl_init_unchained() internal initializer {}

    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role, msg.sender);
        _;
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
     */
    function _checkRole(bytes32 role, address account) internal view {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        StringsUpgradeable.toHexString(uint160(account), 20),
                        " is missing role ",
                        StringsUpgradeable.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external override {
        require(account == msg.sender, "71");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal {
        emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
        _roles[role].adminRole = adminRole;
    }

    function _grantRole(bytes32 role, address account) internal {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, msg.sender);
        }
    }

    function _revokeRole(bytes32 role, address account) internal {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, msg.sender);
        }
    }

    uint256[49] private __gap;
}


// File contracts/interfaces/IFeeManager.sol



pragma solidity ^0.8.7;

/// @title IFeeManagerFunctions
/// @author Angle Core Team
/// @dev Interface for the `FeeManager` contract
interface IFeeManagerFunctions is IAccessControl {
    // ================================= Keepers ===================================

    function updateUsersSLP() external;

    function updateHA() external;

    // ================================= Governance ================================

    function deployCollateral(
        address[] memory governorList,
        address guardian,
        address _perpetualManager
    ) external;

    function setFees(
        uint256[] memory xArray,
        uint64[] memory yArray,
        uint8 typeChange
    ) external;

    function setHAFees(uint64 _haFeeDeposit, uint64 _haFeeWithdraw) external;
}

/// @title IFeeManager
/// @author Angle Core Team
/// @notice Previous interface with additionnal getters for public variables and mappings
/// @dev We need these getters as they are used in other contracts of the protocol
interface IFeeManager is IFeeManagerFunctions {
    function stableMaster() external view returns (address);

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


// File @openzeppelin/contracts/utils/introspection/[email protected]



pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}


// File contracts/interfaces/IERC721.sol



pragma solidity ^0.8.7;

interface IERC721 is IERC165 {
    function balanceOf(address owner) external view returns (uint256 balance);

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function approve(address to, uint256 tokenId) external;

    function getApproved(uint256 tokenId) external view returns (address operator);

    function setApprovalForAll(address operator, bool _approved) external;

    function isApprovedForAll(address owner, address operator) external view returns (bool);

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}

interface IERC721Metadata is IERC721 {
    function name() external view returns (string memory);

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

    function tokenURI(uint256 tokenId) external view returns (string memory);
}


// File contracts/interfaces/IOracle.sol



pragma solidity ^0.8.7;

/// @title IOracle
/// @author Angle Core Team
/// @notice Interface for Angle's oracle contracts reading oracle rates from both UniswapV3 and Chainlink
/// from just UniswapV3 or from just Chainlink
interface IOracle {
    function read() external view returns (uint256);

    function readAll() external view returns (uint256 lowerRate, uint256 upperRate);

    function readLower() external view returns (uint256);

    function readUpper() external view returns (uint256);

    function readQuote(uint256 baseAmount) external view returns (uint256);

    function readQuoteLower(uint256 baseAmount) external view returns (uint256);

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


// File contracts/interfaces/IPerpetualManager.sol



pragma solidity ^0.8.7;




/// @title Interface of the contract managing perpetuals
/// @author Angle Core Team
/// @dev Front interface, meaning only user-facing functions
interface IPerpetualManagerFront is IERC721Metadata {
    function openPerpetual(
        address owner,
        uint256 amountBrought,
        uint256 amountCommitted,
        uint256 maxOracleRate,
        uint256 minNetMargin
    ) external returns (uint256 perpetualID);

    function closePerpetual(
        uint256 perpetualID,
        address to,
        uint256 minCashOutAmount
    ) external;

    function addToPerpetual(uint256 perpetualID, uint256 amount) external;

    function removeFromPerpetual(
        uint256 perpetualID,
        uint256 amount,
        address to
    ) external;

    function liquidatePerpetuals(uint256[] memory perpetualIDs) external;

    function forceClosePerpetuals(uint256[] memory perpetualIDs) external;

    // ========================= External View Functions =============================

    function getCashOutAmount(uint256 perpetualID, uint256 rate) external view returns (uint256, uint256);

    function isApprovedOrOwner(address spender, uint256 perpetualID) external view returns (bool);
}

/// @title Interface of the contract managing perpetuals
/// @author Angle Core Team
/// @dev This interface does not contain user facing functions, it just has functions that are
/// interacted with in other parts of the protocol
interface IPerpetualManagerFunctions is IAccessControl {
    // ================================= Governance ================================

    function deployCollateral(
        address[] memory governorList,
        address guardian,
        IFeeManager feeManager,
        IOracle oracle_
    ) external;

    function setFeeManager(IFeeManager feeManager_) external;

    function setHAFees(
        uint64[] memory _xHAFees,
        uint64[] memory _yHAFees,
        uint8 deposit
    ) external;

    function setTargetAndLimitHAHedge(uint64 _targetHAHedge, uint64 _limitHAHedge) external;

    function setKeeperFeesLiquidationRatio(uint64 _keeperFeesLiquidationRatio) external;

    function setKeeperFeesCap(uint256 _keeperFeesLiquidationCap, uint256 _keeperFeesClosingCap) external;

    function setKeeperFeesClosing(uint64[] memory _xKeeperFeesClosing, uint64[] memory _yKeeperFeesClosing) external;

    function setLockTime(uint64 _lockTime) external;

    function setBoundsPerpetual(uint64 _maxLeverage, uint64 _maintenanceMargin) external;

    function pause() external;

    function unpause() external;

    // ==================================== Keepers ================================

    function setFeeKeeper(uint64 feeDeposit, uint64 feesWithdraw) external;

    // =============================== StableMaster ================================

    function setOracle(IOracle _oracle) external;
}

/// @title IPerpetualManager
/// @author Angle Core Team
/// @notice Previous interface with additionnal getters for public variables
interface IPerpetualManager is IPerpetualManagerFunctions {
    function poolManager() external view returns (address);

    function oracle() external view returns (address);

    function targetHAHedge() external view returns (uint64);

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


// File contracts/interfaces/IPoolManager.sol



pragma solidity ^0.8.7;



// Struct for the parameters associated to a strategy interacting with a collateral `PoolManager`
// contract
struct StrategyParams {
    // Timestamp of last report made by this strategy
    // It is also used to check if a strategy has been initialized
    uint256 lastReport;
    // Total amount the strategy is expected to have
    uint256 totalStrategyDebt;
    // The share of the total assets in the `PoolManager` contract that the `strategy` can access to.
    uint256 debtRatio;
}

/// @title IPoolManagerFunctions
/// @author Angle Core Team
/// @notice Interface for the collateral poolManager contracts handling each one type of collateral for
/// a given stablecoin
/// @dev Only the functions used in other contracts of the protocol are left here
interface IPoolManagerFunctions {
    // ============================ Constructor ====================================

    function deployCollateral(
        address[] memory governorList,
        address guardian,
        IPerpetualManager _perpetualManager,
        IFeeManager feeManager,
        IOracle oracle
    ) external;

    // ============================ Yield Farming ==================================

    function creditAvailable() external view returns (uint256);

    function debtOutstanding() external view returns (uint256);

    function report(
        uint256 _gain,
        uint256 _loss,
        uint256 _debtPayment
    ) external;

    // ============================ Governance =====================================

    function addGovernor(address _governor) external;

    function removeGovernor(address _governor) external;

    function setGuardian(address _guardian, address guardian) external;

    function revokeGuardian(address guardian) external;

    function setFeeManager(IFeeManager _feeManager) external;

    // ============================= Getters =======================================

    function getBalance() external view returns (uint256);

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

/// @title IPoolManager
/// @author Angle Core Team
/// @notice Previous interface with additionnal getters for public variables and mappings
/// @dev Used in other contracts of the protocol
interface IPoolManager is IPoolManagerFunctions {
    function stableMaster() external view returns (address);

    function perpetualManager() external view returns (address);

    function token() external view returns (address);

    function feeManager() external view returns (address);

    function totalDebt() external view returns (uint256);

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


// File contracts/interfaces/IStakingRewards.sol



pragma solidity ^0.8.7;

/// @title IStakingRewardsFunctions
/// @author Angle Core Team
/// @notice Interface for the staking rewards contract that interact with the `RewardsDistributor` contract
interface IStakingRewardsFunctions {
    function notifyRewardAmount(uint256 reward) external;

    function recoverERC20(
        address tokenAddress,
        address to,
        uint256 tokenAmount
    ) external;

    function setNewRewardsDistribution(address newRewardsDistribution) external;
}

/// @title IStakingRewards
/// @author Angle Core Team
/// @notice Previous interface with additionnal getters for public variables
interface IStakingRewards is IStakingRewardsFunctions {
    function rewardToken() external view returns (IERC20);
}


// File contracts/interfaces/IRewardsDistributor.sol



pragma solidity ^0.8.7;

/// @title IRewardsDistributor
/// @author Angle Core Team, inspired from Fei protocol
/// (https://github.com/fei-protocol/fei-protocol-core/blob/master/contracts/staking/IRewardsDistributor.sol)
/// @notice Rewards Distributor interface
interface IRewardsDistributor {
    // ========================= Public Parameter Getter ===========================

    function rewardToken() external view returns (IERC20);

    // ======================== External User Available Function ===================

    function drip(IStakingRewards stakingContract) external returns (uint256);

    // ========================= Governor Functions ================================

    function governorWithdrawRewardToken(uint256 amount, address governance) external;

    function governorRecover(
        address tokenAddress,
        address to,
        uint256 amount,
        IStakingRewards stakingContract
    ) external;

    function setUpdateFrequency(uint256 _frequency, IStakingRewards stakingContract) external;

    function setIncentiveAmount(uint256 _incentiveAmount, IStakingRewards stakingContract) external;

    function setAmountToDistribute(uint256 _amountToDistribute, IStakingRewards stakingContract) external;

    function setDuration(uint256 _duration, IStakingRewards stakingContract) external;

    function setStakingContract(
        address _stakingContract,
        uint256 _duration,
        uint256 _incentiveAmount,
        uint256 _dripFrequency,
        uint256 _amountToDistribute
    ) external;

    function setNewRewardsDistributor(address newRewardsDistributor) external;

    function removeStakingContract(IStakingRewards stakingContract) external;
}


// File @openzeppelin/contracts-upgradeable/token/ERC20/[email protected]



pragma solidity ^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 contracts/interfaces/ISanToken.sol



pragma solidity ^0.8.7;

/// @title ISanToken
/// @author Angle Core Team
/// @notice Interface for Angle's `SanToken` contract that handles sanTokens, tokens that are given to SLPs
/// contributing to a collateral for a given stablecoin
interface ISanToken is IERC20Upgradeable {
    // ================================== StableMaster =============================

    function mint(address account, uint256 amount) external;

    function burnFrom(
        uint256 amount,
        address burner,
        address sender
    ) external;

    function burnSelf(uint256 amount, address burner) external;

    function stableMaster() external view returns (address);

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


// File contracts/interfaces/IStableMaster.sol



pragma solidity ^0.8.7;

// Normally just importing `IPoolManager` should be sufficient, but for clarity here
// we prefer to import all concerned interfaces




// Struct to handle all the parameters to manage the fees
// related to a given collateral pool (associated to the stablecoin)
struct MintBurnData {
    // Values of the thresholds to compute the minting fees
    // depending on HA hedge (scaled by `BASE_PARAMS`)
    uint64[] xFeeMint;
    // Values of the fees at thresholds (scaled by `BASE_PARAMS`)
    uint64[] yFeeMint;
    // Values of the thresholds to compute the burning fees
    // depending on HA hedge (scaled by `BASE_PARAMS`)
    uint64[] xFeeBurn;
    // Values of the fees at thresholds (scaled by `BASE_PARAMS`)
    uint64[] yFeeBurn;
    // Max proportion of collateral from users that can be covered by HAs
    // It is exactly the same as the parameter of the same name in `PerpetualManager`, whenever one is updated
    // the other changes accordingly
    uint64 targetHAHedge;
    // Minting fees correction set by the `FeeManager` contract: they are going to be multiplied
    // to the value of the fees computed using the hedge curve
    // Scaled by `BASE_PARAMS`
    uint64 bonusMalusMint;
    // Burning fees correction set by the `FeeManager` contract: they are going to be multiplied
    // to the value of the fees computed using the hedge curve
    // Scaled by `BASE_PARAMS`
    uint64 bonusMalusBurn;
    // Parameter used to limit the number of stablecoins that can be issued using the concerned collateral
    uint256 capOnStableMinted;
}

// Struct to handle all the variables and parameters to handle SLPs in the protocol
// including the fraction of interests they receive or the fees to be distributed to
// them
struct SLPData {
    // Last timestamp at which the `sanRate` has been updated for SLPs
    uint256 lastBlockUpdated;
    // Fees accumulated from previous blocks and to be distributed to SLPs
    uint256 lockedInterests;
    // Max interests used to update the `sanRate` in a single block
    // Should be in collateral token base
    uint256 maxInterestsDistributed;
    // Amount of fees left aside for SLPs and that will be distributed
    // when the protocol is collateralized back again
    uint256 feesAside;
    // Part of the fees normally going to SLPs that is left aside
    // before the protocol is collateralized back again (depends on collateral ratio)
    // Updated by keepers and scaled by `BASE_PARAMS`
    uint64 slippageFee;
    // Portion of the fees from users minting and burning
    // that goes to SLPs (the rest goes to surplus)
    uint64 feesForSLPs;
    // Slippage factor that's applied to SLPs exiting (depends on collateral ratio)
    // If `slippage = BASE_PARAMS`, SLPs can get nothing, if `slippage = 0` they get their full claim
    // Updated by keepers and scaled by `BASE_PARAMS`
    uint64 slippage;
    // Portion of the interests from lending
    // that goes to SLPs (the rest goes to surplus)
    uint64 interestsForSLPs;
}

/// @title IStableMasterFunctions
/// @author Angle Core Team
/// @notice Interface for the `StableMaster` contract
interface IStableMasterFunctions {
    function deploy(
        address[] memory _governorList,
        address _guardian,
        address _agToken
    ) external;

    // ============================== Lending ======================================

    function accumulateInterest(uint256 gain) external;

    function signalLoss(uint256 loss) external;

    // ============================== HAs ==========================================

    function getStocksUsers() external view returns (uint256 maxCAmountInStable);

    function convertToSLP(uint256 amount, address user) external;

    // ============================== Keepers ======================================

    function getCollateralRatio() external returns (uint256);

    function setFeeKeeper(
        uint64 feeMint,
        uint64 feeBurn,
        uint64 _slippage,
        uint64 _slippageFee
    ) external;

    // ============================== AgToken ======================================

    function updateStocksUsers(uint256 amount, address poolManager) external;

    // ============================= Governance ====================================

    function setCore(address newCore) external;

    function addGovernor(address _governor) external;

    function removeGovernor(address _governor) external;

    function setGuardian(address newGuardian, address oldGuardian) external;

    function revokeGuardian(address oldGuardian) external;

    function setCapOnStableAndMaxInterests(
        uint256 _capOnStableMinted,
        uint256 _maxInterestsDistributed,
        IPoolManager poolManager
    ) external;

    function setIncentivesForSLPs(
        uint64 _feesForSLPs,
        uint64 _interestsForSLPs,
        IPoolManager poolManager
    ) external;

    function setUserFees(
        IPoolManager poolManager,
        uint64[] memory _xFee,
        uint64[] memory _yFee,
        uint8 _mint
    ) external;

    function setTargetHAHedge(uint64 _targetHAHedge) external;

    function pause(bytes32 agent, IPoolManager poolManager) external;

    function unpause(bytes32 agent, IPoolManager poolManager) external;
}

/// @title IStableMaster
/// @author Angle Core Team
/// @notice Previous interface with additionnal getters for public variables and mappings
interface IStableMaster is IStableMasterFunctions {
    function agToken() external view returns (address);

    function collateralMap(IPoolManager poolManager)
        external
        view
        returns (
            IERC20 token,
            ISanToken sanToken,
            IPerpetualManager perpetualManager,
            IOracle oracle,
            uint256 stocksUsers,
            uint256 sanRate,
            uint256 collatBase,
            SLPData memory slpData,
            MintBurnData memory feeData
        );
}


// File contracts/utils/FunctionUtils.sol



pragma solidity ^0.8.7;

/// @title FunctionUtils
/// @author Angle Core Team
/// @notice Contains all the utility functions that are needed in different places of the protocol
/// @dev Functions in this contract should typically be pure functions
/// @dev This contract is voluntarily a contract and not a library to save some gas cost every time it is used
contract FunctionUtils {
    /// @notice Base that is used to compute ratios and floating numbers
    uint256 public constant BASE_TOKENS = 10**18;
    /// @notice Base that is used to define parameters that need to have a floating value (for instance parameters
    /// that are defined as ratios)
    uint256 public constant BASE_PARAMS = 10**9;

    /// @notice Computes the value of a linear by part function at a given point
    /// @param x Point of the function we want to compute
    /// @param xArray List of breaking points (in ascending order) that define the linear by part function
    /// @param yArray List of values at breaking points (not necessarily in ascending order)
    /// @dev The evolution of the linear by part function between two breaking points is linear
    /// @dev Before the first breaking point and after the last one, the function is constant with a value
    /// equal to the first or last value of the yArray
    /// @dev This function is relevant if `x` is between O and `BASE_PARAMS`. If `x` is greater than that, then
    /// everything will be as if `x` is equal to the greater element of the `xArray`
    function _piecewiseLinear(
        uint64 x,
        uint64[] memory xArray,
        uint64[] memory yArray
    ) internal pure returns (uint64) {
        if (x >= xArray[xArray.length - 1]) {
            return yArray[xArray.length - 1];
        } else if (x <= xArray[0]) {
            return yArray[0];
        } else {
            uint256 lower;
            uint256 upper = xArray.length - 1;
            uint256 mid;
            while (upper - lower > 1) {
                mid = lower + (upper - lower) / 2;
                if (xArray[mid] <= x) {
                    lower = mid;
                } else {
                    upper = mid;
                }
            }
            if (yArray[upper] > yArray[lower]) {
                // There is no risk of overflow here as in the product of the difference of `y`
                // with the difference of `x`, the product is inferior to `BASE_PARAMS**2` which does not
                // overflow for `uint64`
                return
                    yArray[lower] +
                    ((yArray[upper] - yArray[lower]) * (x - xArray[lower])) /
                    (xArray[upper] - xArray[lower]);
            } else {
                return
                    yArray[lower] -
                    ((yArray[lower] - yArray[upper]) * (x - xArray[lower])) /
                    (xArray[upper] - xArray[lower]);
            }
        }
    }

    /// @notice Checks if the input arrays given by governance to update the fee structure is valid
    /// @param xArray List of breaking points (in ascending order) that define the linear by part function
    /// @param yArray List of values at breaking points (not necessarily in ascending order)
    /// @dev This function is a way to avoid some governance attacks or errors
    /// @dev The modifier checks if the arrays have a non null length, if their length is the same, if the values
    /// in the `xArray` are in ascending order and if the values in the `xArray` and in the `yArray` are not superior
    /// to `BASE_PARAMS`
    modifier onlyCompatibleInputArrays(uint64[] memory xArray, uint64[] memory yArray) {
        require(xArray.length == yArray.length && xArray.length > 0, "5");
        for (uint256 i = 0; i <= yArray.length - 1; i++) {
            require(yArray[i] <= uint64(BASE_PARAMS) && xArray[i] <= uint64(BASE_PARAMS), "6");
            if (i > 0) {
                require(xArray[i] > xArray[i - 1], "7");
            }
        }
        _;
    }

    /// @notice Checks if the new value given for the parameter is consistent (it should be inferior to 1
    /// if it corresponds to a ratio)
    /// @param fees Value of the new parameter to check
    modifier onlyCompatibleFees(uint64 fees) {
        require(fees <= BASE_PARAMS, "4");
        _;
    }

    /// @notice Checks if the new address given is not null
    /// @param newAddress Address to check
    /// @dev Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#missing-zero-address-validation
    modifier zeroCheck(address newAddress) {
        require(newAddress != address(0), "0");
        _;
    }
}


// File contracts/perpetualManager/PerpetualManagerEvents.sol



pragma solidity ^0.8.7;















// Used in the `forceCashOutPerpetuals` function to store owners of perpetuals which have been force cashed
// out, along with the amount associated to it
struct Pairs {
    address owner;
    uint256 netCashOutAmount;
}

/// @title PerpetualManagerEvents
/// @author Angle Core Team
/// @notice `PerpetualManager` is the contract handling all the Hedging Agents perpetuals
/// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol
/// @dev This file contains all the events of the `PerpetualManager` contract
contract PerpetualManagerEvents {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    event PerpetualUpdated(uint256 _perpetualID, uint256 _margin);

    event PerpetualOpened(uint256 _perpetualID, uint256 _entryRate, uint256 _margin, uint256 _committedAmount);

    event PerpetualClosed(uint256 _perpetualID, uint256 _closeAmount);

    event PerpetualsForceClosed(uint256[] perpetualIDs, Pairs[] ownerAndCashOut, address keeper, uint256 reward);

    event KeeperTransferred(address keeperAddress, uint256 liquidationFees);

    // ============================== Parameters ===================================

    event BaseURIUpdated(string _baseURI);

    event LockTimeUpdated(uint64 _lockTime);

    event KeeperFeesCapUpdated(uint256 _keeperFeesLiquidationCap, uint256 _keeperFeesClosingCap);

    event TargetAndLimitHAHedgeUpdated(uint64 _targetHAHedge, uint64 _limitHAHedge);

    event BoundsPerpetualUpdated(uint64 _maxLeverage, uint64 _maintenanceMargin);

    event HAFeesUpdated(uint64[] _xHAFees, uint64[] _yHAFees, uint8 deposit);

    event KeeperFeesLiquidationRatioUpdated(uint64 _keeperFeesLiquidationRatio);

    event KeeperFeesClosingUpdated(uint64[] xKeeperFeesClosing, uint64[] yKeeperFeesClosing);

    // =============================== Reward ======================================

    event RewardAdded(uint256 _reward);

    event RewardPaid(address indexed _user, uint256 _reward);

    event RewardsDistributionUpdated(address indexed _rewardsDistributor);

    event RewardsDistributionDurationUpdated(uint256 _rewardsDuration, address indexed _rewardsDistributor);

    event Recovered(address indexed tokenAddress, address indexed to, uint256 amount);
}


// File contracts/perpetualManager/PerpetualManagerStorage.sol



pragma solidity ^0.8.7;

struct Perpetual {
    // Oracle value at the moment of perpetual opening
    uint256 entryRate;
    // Timestamp at which the perpetual was opened
    uint256 entryTimestamp;
    // Amount initially brought in the perpetual (net from fees) + amount added - amount removed from it
    // This is the only element that can be modified in the perpetual after its creation
    uint256 margin;
    // Amount of collateral covered by the perpetual. This cannot be modified once the perpetual is opened.
    // The amount covered is used interchangeably with the amount hedged
    uint256 committedAmount;
}

/// @title PerpetualManagerStorage
/// @author Angle Core Team
/// @notice `PerpetualManager` is the contract handling all the Hedging Agents positions and perpetuals
/// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol
/// @dev This file contains all the parameters and references used in the `PerpetualManager` contract
// solhint-disable-next-line max-states-count
contract PerpetualManagerStorage is PerpetualManagerEvents, FunctionUtils {
    // Base used in the collateral implementation (ERC20 decimal)
    uint256 internal _collatBase;

    // ============================== Perpetual Variables ==========================

    /// @notice Total amount of stablecoins that are insured (i.e. that could be redeemed against
    /// collateral thanks to HAs)
    /// When a HA opens a perpetual, it covers/hedges a fixed amount of stablecoins for the protocol, equal to
    /// the committed amount times the entry rate
    /// `totalHedgeAmount` is the sum of all these hedged amounts
    uint256 public totalHedgeAmount;

    // Counter to generate a unique `perpetualID` for each perpetual
    CountersUpgradeable.Counter internal _perpetualIDcount;

    // ========================== Mutable References ============================

    /// @notice `Oracle` to give the rate feed, that is the price of the collateral
    /// with respect to the price of the stablecoin
    /// This reference can be modified by the corresponding `StableMaster` contract
    IOracle public oracle;

    // `FeeManager` address allowed to update the way fees are computed for this contract
    // This reference can be modified by the `PoolManager` contract
    IFeeManager internal _feeManager;

    // ========================== Immutable References ==========================

    /// @notice Interface for the `rewardToken` distributed as a reward
    /// As of Angle V1, only a single `rewardToken` can be distributed to HAs who own a perpetual
    /// This implementation assumes that reward tokens have a base of 18 decimals
    IERC20 public rewardToken;

    /// @notice Address of the `PoolManager` instance
    IPoolManager public poolManager;

    // Address of the `StableMaster` instance
    IStableMaster internal _stableMaster;

    // Interface for the underlying token accepted by this contract
    // This reference cannot be changed, it is taken from the `PoolManager`
    IERC20 internal _token;

    // ======================= Fees and other Parameters ===========================

    /// Deposit fees for HAs depend on the hedge ratio that is the ratio between what is hedged
    /// (or covered, this is a synonym) by HAs compared with the total amount to hedge
    /// @notice Thresholds for the ratio between to amount hedged and the amount to hedge
    /// The bigger the ratio the bigger the fees will be because this means that the max amount
    /// to insure is soon to be reached
    uint64[] public xHAFeesDeposit;

    /// @notice Deposit fees at threshold values
    /// This array should have the same length as the array above
    /// The evolution of the fees between two threshold values is linear
    uint64[] public yHAFeesDeposit;

    /// Withdraw fees for HAs also depend on the hedge ratio
    /// @notice Thresholds for the hedge ratio
    uint64[] public xHAFeesWithdraw;

    /// @notice Withdraw fees at threshold values
    uint64[] public yHAFeesWithdraw;

    /// @notice Maintenance Margin (in `BASE_PARAMS`) for each perpetual
    /// The margin ratio is defined for a perpetual as: `(initMargin + PnL) / committedAmount` where
    /// `PnL = committedAmount * (1 - initRate/currentRate)`
    /// If the `marginRatio` is below `maintenanceMargin`: then the perpetual can be liquidated
    uint64 public maintenanceMargin;

    /// @notice Maximum leverage multiplier authorized for HAs (`in BASE_PARAMS`)
    /// Leverage for a perpetual here corresponds to the ratio between the amount committed
    /// and the margin of the perpetual
    uint64 public maxLeverage;

    /// @notice Target proportion of stablecoins issued using this collateral to insure with HAs.
    /// This variable is exactly the same as the one in the `StableMaster` contract for this collateral.
    /// Above this hedge ratio, HAs cannot open new perpetuals
    /// When keepers are forcing the closing of some perpetuals, they are incentivized to bringing
    /// the hedge ratio to this proportion
    uint64 public targetHAHedge;

    /// @notice Limit proportion of stablecoins issued using this collateral that HAs can insure
    /// Above this ratio `forceCashOut` is activated and anyone can see its perpetual cashed out
    uint64 public limitHAHedge;

    /// @notice Extra parameter from the `FeeManager` contract that is multiplied to the fees from above and that
    /// can be used to change deposit fees. It works as a bonus - malus fee, if `haBonusMalusDeposit > BASE_PARAMS`,
    /// then the fee will be larger than `haFeesDeposit`, if `haBonusMalusDeposit < BASE_PARAMS`, fees will be smaller.
    /// This parameter, updated by keepers in the `FeeManager` contract, could most likely depend on the collateral ratio
    uint64 public haBonusMalusDeposit;

    /// @notice Extra parameter from the `FeeManager` contract that is multiplied to the fees from above and that
    /// can be used to change withdraw fees. It works as a bonus - malus fee, if `haBonusMalusWithdraw > BASE_PARAMS`,
    /// then the fee will be larger than `haFeesWithdraw`, if `haBonusMalusWithdraw < BASE_PARAMS`, fees will be smaller
    uint64 public haBonusMalusWithdraw;

    /// @notice Amount of time before HAs are allowed to withdraw funds from their perpetuals
    /// either using `removeFromPerpetual` or `closePerpetual`. New perpetuals cannot be forced closed in
    /// situations where the `forceClosePerpetuals` function is activated before this `lockTime` elapsed
    uint64 public lockTime;

    // ================================= Keeper fees ======================================
    // All these parameters can be modified by their corresponding governance function

    /// @notice Portion of the leftover cash out amount of liquidated perpetuals that go to
    /// liquidating keepers
    uint64 public keeperFeesLiquidationRatio;

    /// @notice Cap on the fees that go to keepers liquidating a perpetual
    /// If a keeper liquidates n perpetuals in a single transaction, then this keeper is entitled to get as much as
    /// `n * keeperFeesLiquidationCap` as a reward
    uint256 public keeperFeesLiquidationCap;

    /// @notice Cap on the fees that go to keepers closing perpetuals when too much collateral is hedged by HAs
    /// (hedge ratio above `limitHAHedge`)
    /// If a keeper forces the closing of n perpetuals in a single transaction, then this keeper is entitled to get
    /// as much as `keeperFeesClosingCap`. This cap amount is independent of the number of perpetuals closed
    uint256 public keeperFeesClosingCap;

    /// @notice Thresholds on the values of the rate between the current hedged amount (`totalHedgeAmount`) and the
    /// target hedged amount by HAs (`targetHedgeAmount`) divided by 2. A value of `0.5` corresponds to a hedge ratio
    /// of `1`. Doing this allows to maintain an array with values of `x` inferior to `BASE_PARAMS`.
    uint64[] public xKeeperFeesClosing;

    /// @notice Values at thresholds of the proportions of the fees that should go to keepers closing perpetuals
    uint64[] public yKeeperFeesClosing;

    // =========================== Staking Parameters ==============================

    /// @notice Below are parameters that can also be found in other staking contracts
    /// to be able to compute rewards from staking (having perpetuals here) correctly
    uint256 public periodFinish;
    uint256 public rewardRate;
    uint256 public rewardsDuration;
    uint256 public lastUpdateTime;
    uint256 public rewardPerTokenStored;
    address public rewardsDistribution;

    // ============================== ERC721 Base URI ==============================

    /// @notice URI used for the metadata of the perpetuals
    string public baseURI;

    // =============================== Mappings ====================================

    /// @notice Mapping from `perpetualID` to perpetual data
    mapping(uint256 => Perpetual) public perpetualData;

    /// @notice Mapping used to compute the rewards earned by a perpetual in a timeframe
    mapping(uint256 => uint256) public perpetualRewardPerTokenPaid;

    /// @notice Mapping used to get how much rewards in governance tokens are gained by a perpetual
    // identified by its ID
    mapping(uint256 => uint256) public rewards;

    // Mapping from `perpetualID` to owner address
    mapping(uint256 => address) internal _owners;

    // Mapping from owner address to perpetual owned count
    mapping(address => uint256) internal _balances;

    // Mapping from `perpetualID` to approved address
    mapping(uint256 => address) internal _perpetualApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) internal _operatorApprovals;
}


// File contracts/perpetualManager/PerpetualManagerInternal.sol



pragma solidity ^0.8.7;

/// @title PerpetualManagerInternal
/// @author Angle Core Team
/// @notice `PerpetualManager` is the contract handling all the Hedging Agents perpetuals
/// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol
/// @dev This file contains all the internal functions of the `PerpetualManager` contract
contract PerpetualManagerInternal is PerpetualManagerStorage {
    using Address for address;
    using SafeERC20 for IERC20;

    // ======================== State Modifying Functions ==========================

    /// @notice Cashes out a perpetual, which means that it simply deletes the references to the perpetual
    /// in the contract
    /// @param perpetualID ID of the perpetual
    /// @param perpetual Data of the perpetual
    function _closePerpetual(uint256 perpetualID, Perpetual memory perpetual) internal {
        // Handling the staking logic
        // Reward should always be updated before the `totalHedgeAmount`
        // Rewards are distributed to the perpetual which is liquidated
        uint256 hedge = perpetual.committedAmount * perpetual.entryRate;
        _getReward(perpetualID, hedge);
        delete perpetualRewardPerTokenPaid[perpetualID];

        // Updating `totalHedgeAmount` to represent the fact that less money is insured
        totalHedgeAmount -= hedge / _collatBase;

        _burn(perpetualID);
    }

    /// @notice Allows the protocol to transfer collateral to an address while handling the case where there are
    /// not enough reserves
    /// @param owner Address of the receiver
    /// @param amount The amount of collateral sent
    /// @dev If there is not enough collateral in balance (this can happen when money has been lent to strategies),
    /// then the owner is reimbursed by receiving what is missing in sanTokens at the correct value
    function _secureTransfer(address owner, uint256 amount) internal {
        uint256 curBalance = poolManager.getBalance();
        if (curBalance >= amount && amount > 0) {
            // Case where there is enough in reserves to reimburse the person
            _token.safeTransferFrom(address(poolManager), owner, amount);
        } else if (amount > 0) {
            // When there is not enough to reimburse the entire amount, the protocol reimburses
            // what it can using its reserves and the rest is paid in sanTokens at the current
            // exchange rate
            uint256 amountLeft = amount - curBalance;
            _token.safeTransferFrom(address(poolManager), owner, curBalance);
            _stableMaster.convertToSLP(amountLeft, owner);
        }
    }

    /// @notice Checks whether the perpetual should be liquidated or not, and if so liquidates the perpetual
    /// @param perpetualID ID of the perpetual to check and potentially liquidate
    /// @param perpetual Data of the perpetual to check
    /// @param rateDown Oracle value to compute the cash out amount of the perpetual
    /// @return Cash out amount of the perpetual
    /// @return Whether the perpetual was liquidated or not
    /// @dev Generally, to check for the liquidation of a perpetual, we use the lowest oracle value possible:
    /// it's the one that is most at the advantage of the protocol, hence the `rateDown` parameter
    function _checkLiquidation(
        uint256 perpetualID,
        Perpetual memory perpetual,
        uint256 rateDown
    ) internal returns (uint256, uint256) {
        uint256 liquidated;
        (uint256 cashOutAmount, uint256 reachMaintenanceMargin) = _getCashOutAmount(perpetual, rateDown);
        if (cashOutAmount == 0 || reachMaintenanceMargin == 1) {
            _closePerpetual(perpetualID, perpetual);
            // No need for an event to find out that a perpetual is liquidated
            liquidated = 1;
        }
        return (cashOutAmount, liquidated);
    }

    // ========================= Internal View Functions ===========================

    /// @notice Gets the current cash out amount of a perpetual
    /// @param perpetual Data of the concerned perpetual
    /// @param rate Value of the oracle
    /// @return cashOutAmount Amount that the HA could get by closing this perpetual
    /// @return reachMaintenanceMargin Whether the position of the perpetual is now too small
    /// compared with its initial position
    /// @dev Refer to the whitepaper or the doc for the formulas of the cash out amount
    /// @dev The notion of `maintenanceMargin` is standard in centralized platforms offering perpetual futures
    function _getCashOutAmount(Perpetual memory perpetual, uint256 rate)
        internal
        view
        returns (uint256 cashOutAmount, uint256 reachMaintenanceMargin)
    {
        // All these computations are made just because we are working with uint and not int
        // so we cannot do x-y if x<y
        uint256 newCommit = (perpetual.committedAmount * perpetual.entryRate) / rate;
        // Checking if a liquidation is needed: for this to happen the `cashOutAmount` should be inferior
        // to the maintenance margin of the perpetual
        reachMaintenanceMargin;
        if (newCommit >= perpetual.committedAmount + perpetual.margin) cashOutAmount = 0;
        else {
            // The definition of the margin ratio is `(margin + PnL) / committedAmount`
            // where `PnL = commit * (1-entryRate/currentRate)`
            // So here: `newCashOutAmount = margin + PnL`
            cashOutAmount = perpetual.committedAmount + perpetual.margin - newCommit;
            if (cashOutAmount * BASE_PARAMS <= perpetual.committedAmount * maintenanceMargin)
                reachMaintenanceMargin = 1;
        }
    }

    /// @notice Calls the oracle to read both Chainlink and Uniswap rates
    /// @return The lowest oracle value (between Chainlink and Uniswap) is the first outputted value
    /// @return The highest oracle value is the second output
    /// @dev If the oracle only involves a single oracle fees (like just Chainlink for USD-EUR),
    /// the same value is returned twice
    function _getOraclePrice() internal view returns (uint256, uint256) {
        return oracle.readAll();
    }

    /// @notice Computes the incentive for the keeper as a function of the cash out amount of a liquidated perpetual
    /// which value falls below its maintenance margin
    /// @param cashOutAmount Value remaining in the perpetual
    /// @dev By computing keeper fees as a fraction of the cash out amount of a perpetual rather than as a fraction
    /// of the `committedAmount`, keepers are incentivized to react fast when a perpetual is below the maintenance margin
    /// @dev Perpetual exchange protocols typically compute liquidation fees using an equivalent of the `committedAmount`,
    /// this is not the case here
    function _computeKeeperLiquidationFees(uint256 cashOutAmount) internal view returns (uint256 keeperFees) {
        keeperFees = (cashOutAmount * keeperFeesLiquidationRatio) / BASE_PARAMS;
        keeperFees = keeperFees < keeperFeesLiquidationCap ? keeperFees : keeperFeesLiquidationCap;
    }

    /// @notice Gets the value of the hedge ratio that is the ratio between the amount currently hedged by HAs
    /// and the target amount that should be hedged by them
    /// @param currentHedgeAmount Amount currently covered by HAs
    /// @return ratio Ratio between the amount of collateral (in stablecoin value) currently hedged
    /// and the target amount to hedge
    function _computeHedgeRatio(uint256 currentHedgeAmount) internal view returns (uint64 ratio) {
        // Fetching info from the `StableMaster`: the amount to hedge is based on the `stocksUsers`
        // of the given collateral
        uint256 targetHedgeAmount = (_stableMaster.getStocksUsers() * targetHAHedge) / BASE_PARAMS;
        if (currentHedgeAmount < targetHedgeAmount)
            ratio = uint64((currentHedgeAmount * BASE_PARAMS) / targetHedgeAmount);
        else ratio = uint64(BASE_PARAMS);
    }

    // =========================== Fee Computation =================================

    /// @notice Gets the net margin corrected from the fees at perpetual opening
    /// @param margin Amount brought in the perpetual at creation
    /// @param totalHedgeAmountUpdate Amount of stablecoins that this perpetual is going to insure
    /// @param committedAmount Committed amount in the perpetual, we need it to compute the fees
    /// paid by the HA
    /// @return netMargin Amount that will be written in the perpetual as the `margin`
    /// @dev The amount of stablecoins insured by a perpetual is `committedAmount * oracleRate / _collatBase`
    function _getNetMargin(
        uint256 margin,
        uint256 totalHedgeAmountUpdate,
        uint256 committedAmount
    ) internal view returns (uint256 netMargin) {
        // Checking if the HA has the right to open a perpetual with such amount
        // If HAs hedge more than the target amount, then new HAs will not be able to create perpetuals
        // The amount hedged by HAs after opening the perpetual is going to be:
        uint64 ratio = _computeHedgeRatio(totalHedgeAmount + totalHedgeAmountUpdate);
        require(ratio < uint64(BASE_PARAMS), "25");
        // Computing the net margin of HAs to store in the perpetual: it consists simply in deducing fees
        // Those depend on how much is already hedged by HAs compared with what's to hedge
        uint256 haFeesDeposit = (haBonusMalusDeposit * _piecewiseLinear(ratio, xHAFeesDeposit, yHAFeesDeposit)) /
            BASE_PARAMS;
        // Fees are rounded to the advantage of the protocol
        haFeesDeposit = committedAmount - (committedAmount * (BASE_PARAMS - haFeesDeposit)) / BASE_PARAMS;
        // Fees are computed based on the committed amount of the perpetual
        // The following reverts if fees are too big compared to the margin
        netMargin = margin - haFeesDeposit;
    }

    /// @notice Gets the net amount to give to a HA (corrected from the fees) in case of a perpetual closing
    /// @param committedAmount Committed amount in the perpetual
    /// @param cashOutAmount The current cash out amount of the perpetual
    /// @param ratio What's hedged divided by what's to hedge
    /// @return netCashOutAmount Amount that will be distributed to the HA
    /// @return feesPaid Amount of fees paid by the HA at perpetual closing
    /// @dev This function is called by the `closePerpetual` and by the `forceClosePerpetuals`
    /// function
    /// @dev The amount of fees paid by the HA is used to compute the incentive given to HAs closing perpetuals
    /// when too much is covered
    function _getNetCashOutAmount(
        uint256 cashOutAmount,
        uint256 committedAmount,
        uint64 ratio
    ) internal view returns (uint256 netCashOutAmount, uint256 feesPaid) {
        feesPaid = (haBonusMalusWithdraw * _piecewiseLinear(ratio, xHAFeesWithdraw, yHAFeesWithdraw)) / BASE_PARAMS;
        // Rounding the fees at the protocol's advantage
        feesPaid = committedAmount - (committedAmount * (BASE_PARAMS - feesPaid)) / BASE_PARAMS;
        if (feesPaid >= cashOutAmount) {
            netCashOutAmount = 0;
            feesPaid = cashOutAmount;
        } else {
            netCashOutAmount = cashOutAmount - feesPaid;
        }
    }

    // ========================= Reward Distribution ===============================

    /// @notice View function to query the last timestamp at which a reward was distributed
    /// @return Current timestamp if a reward is being distributed or the last timestamp
    function _lastTimeRewardApplicable() internal view returns (uint256) {
        uint256 returnValue = block.timestamp < periodFinish ? block.timestamp : periodFinish;
        return returnValue;
    }

    /// @notice Used to actualize the `rewardPerTokenStored`
    /// @dev It adds to the reward per token: the time elapsed since the `rewardPerTokenStored`
    /// was last updated multiplied by the `rewardRate` divided by the number of tokens
    /// @dev Specific attention should be placed on the base here: `rewardRate` is in the base of the reward token
    /// and `totalHedgeAmount` is in `BASE_TOKENS` here: as this function concerns an amount of reward
    /// tokens, the output of this function should be in the base of the reward token too
    function _rewardPerToken() internal view returns (uint256) {
        if (totalHedgeAmount == 0) {
            return rewardPerTokenStored;
        }
        return
            rewardPerTokenStored +
            ((_lastTimeRewardApplicable() - lastUpdateTime) * rewardRate * BASE_TOKENS) /
            totalHedgeAmount;
    }

    /// @notice Allows a perpetual owner to withdraw rewards
    /// @param perpetualID ID of the perpetual which accumulated tokens
    /// @param hedge Perpetual commit amount times the entry rate
    /// @dev Internal version of the `getReward` function
    /// @dev In case where an approved address calls to close a perpetual, rewards are still going to get distributed
    /// to the owner of the perpetual, and not necessarily to the address getting the proceeds of the perpetual
    function _getReward(uint256 perpetualID, uint256 hedge) internal {
        _updateReward(perpetualID, hedge);
        uint256 reward = rewards[perpetualID];
        if (reward > 0) {
            rewards[perpetualID] = 0;
            address owner = _owners[perpetualID];
            // Attention here, there may be reentrancy attacks because of the following call
            // to an external contract done before other things are modified. Yet since the `rewardToken`
            // is mostly going to be a trusted contract controlled by governance (namely the ANGLE token), then
            // there is no point in putting an expensive `nonReentrant` modifier in the functions in `PerpetualManagerFront`
            // that allow indirect interactions with `_updateReward`. If new `rewardTokens` are set, we could think about
            // upgrading the `PerpetualManagerFront` contract
            rewardToken.safeTransfer(owner, reward);
            emit RewardPaid(owner, reward);
        }
    }

    /// @notice Allows to check the amount of gov tokens earned by a perpetual
    /// @param perpetualID ID of the perpetual which accumulated tokens
    /// @param hedge Perpetual commit amount times the entry rate
    /// @return Amount of gov tokens earned by the perpetual
    /// @dev A specific attention should be paid to have the base here: we consider that each HA stakes an amount
    /// equal to `committedAmount * entryRate / _collatBase`, here as the `hedge` corresponds to `committedAmount * entryRate`,
    /// we just need to divide by `_collatBase`
    /// @dev HAs earn reward tokens which are in base `BASE_TOKENS`
    function _earned(uint256 perpetualID, uint256 hedge) internal view returns (uint256) {
        return
            (hedge * (_rewardPerToken() - perpetualRewardPerTokenPaid[perpetualID])) /
            BASE_TOKENS /
            _collatBase +
            rewards[perpetualID];
    }

    /// @notice Updates the amount of gov tokens earned by a perpetual
    /// @param perpetualID of the perpetual which earns tokens
    /// @param hedge Perpetual commit amount times the entry rate
    /// @dev When this function is called in the code, it has already been checked that the `perpetualID`
    /// exists
    function _updateReward(uint256 perpetualID, uint256 hedge) internal {
        rewardPerTokenStored = _rewardPerToken();
        lastUpdateTime = _lastTimeRewardApplicable();
        // No need to check if the `perpetualID` exists here, it has already been checked
        // in the code before when this internal function is called
        rewards[perpetualID] = _earned(perpetualID, hedge);
        perpetualRewardPerTokenPaid[perpetualID] = rewardPerTokenStored;
    }

    // =============================== ERC721 Logic ================================

    /// @notice Gets the owner of a perpetual
    /// @param perpetualID ID of the concerned perpetual
    /// @return owner Owner of the perpetual
    function _ownerOf(uint256 perpetualID) internal view returns (address owner) {
        owner = _owners[perpetualID];
        require(owner != address(0), "2");
    }

    /// @notice Gets the addresses approved for a perpetual
    /// @param perpetualID ID of the concerned perpetual
    /// @return Address approved for this perpetual
    function _getApproved(uint256 perpetualID) internal view returns (address) {
        return _perpetualApprovals[perpetualID];
    }

    /// @notice Safely transfers `perpetualID` token from `from` to `to`, checking first that contract recipients
    /// are aware of the ERC721 protocol to prevent tokens from being forever locked
    /// @param perpetualID ID of the concerned perpetual
    /// @param _data Additional data, it has no specified format and it is sent in call to `to`
    /// @dev This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
    /// implement alternative mechanisms to perform token transfer, such as signature-based
    /// @dev Requirements:
    ///     - `from` cannot be the zero address.
    ///     - `to` cannot be the zero address.
    ///     - `perpetualID` token must exist and be owned by `from`.
    ///     - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    function _safeTransfer(
        address from,
        address to,
        uint256 perpetualID,
        bytes memory _data
    ) internal {
        _transfer(from, to, perpetualID);
        require(_checkOnERC721Received(from, to, perpetualID, _data), "24");
    }

    /// @notice Returns whether `perpetualID` exists
    /// @dev Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}
    /// @dev Tokens start existing when they are minted (`_mint`),
    /// and stop existing when they are burned (`_burn`)
    function _exists(uint256 perpetualID) internal view returns (bool) {
        return _owners[perpetualID] != address(0);
    }

    /// @notice Returns whether `spender` is allowed to manage `perpetualID`
    /// @dev `perpetualID` must exist
    function _isApprovedOrOwner(address spender, uint256 perpetualID) internal view returns (bool) {
        // The following checks if the perpetual exists
        address owner = _ownerOf(perpetualID);
        return (spender == owner || _getApproved(perpetualID) == spender || _operatorApprovals[owner][spender]);
    }

    /// @notice Mints `perpetualID` and transfers it to `to`
    /// @dev This method is equivalent to the `_safeMint` method used in OpenZeppelin ERC721 contract
    /// @dev `perpetualID` must not exist and `to` cannot be the zero address
    /// @dev Before calling this function it is checked that the `perpetualID` does not exist as it
    /// comes from a counter that has been incremented
    /// @dev Emits a {Transfer} event
    function _mint(address to, uint256 perpetualID) internal {
        _balances[to] += 1;
        _owners[perpetualID] = to;
        emit Transfer(address(0), to, perpetualID);
        require(_checkOnERC721Received(address(0), to, perpetualID, ""), "24");
    }

    /// @notice Destroys `perpetualID`
    /// @dev `perpetualID` must exist
    /// @dev Emits a {Transfer} event
    function _burn(uint256 perpetualID) internal {
        address owner = _ownerOf(perpetualID);

        // Clear approvals
        _approve(address(0), perpetualID);

        _balances[owner] -= 1;
        delete _owners[perpetualID];
        delete perpetualData[perpetualID];

        emit Transfer(owner, address(0), perpetualID);
    }

    /// @notice Transfers `perpetualID` from `from` to `to` as opposed to {transferFrom},
    /// this imposes no restrictions on msg.sender
    /// @dev `to` cannot be the zero address and `perpetualID` must be owned by `from`
    /// @dev Emits a {Transfer} event
    function _transfer(
        address from,
        address to,
        uint256 perpetualID
    ) internal {
        require(_ownerOf(perpetualID) == from, "1");
        require(to != address(0), "26");

        // Clear approvals from the previous owner
        _approve(address(0), perpetualID);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[perpetualID] = to;

        emit Transfer(from, to, perpetualID);
    }

    /// @notice Approves `to` to operate on `perpetualID`
    function _approve(address to, uint256 perpetualID) internal {
        _perpetualApprovals[perpetualID] = to;
        emit Approval(_ownerOf(perpetualID), to, perpetualID);
    }

    /// @notice Internal function to invoke {IERC721Receiver-onERC721Received} on a target address
    /// The call is not executed if the target address is not a contract
    /// @param from Address representing the previous owner of the given token ID
    /// @param to Target address that will receive the tokens
    /// @param perpetualID ID of the token to be transferred
    /// @param _data Bytes optional data to send along with the call
    /// @return Bool whether the call correctly returned the expected magic value
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 perpetualID,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721ReceiverUpgradeable(to).onERC721Received(msg.sender, from, perpetualID, _data) returns (
                bytes4 retval
            ) {
                return retval == IERC721ReceiverUpgradeable(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("24");
                } else {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }
}


// File contracts/perpetualManager/PerpetualManager.sol



pragma solidity ^0.8.7;

/// @title PerpetualManager
/// @author Angle Core Team
/// @notice `PerpetualManager` is the contract handling all the Hedging Agents positions and perpetuals
/// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol
/// @dev This file contains the functions of the `PerpetualManager` that can be interacted with
/// by `StableMaster`, by the `PoolManager`, by the `FeeManager` and by governance
contract PerpetualManager is
    PerpetualManagerInternal,
    IPerpetualManagerFunctions,
    IStakingRewardsFunctions,
    AccessControlUpgradeable,
    PausableUpgradeable
{
    using SafeERC20 for IERC20;

    /// @notice Role for guardians, governors and `StableMaster`
    /// Made for the `StableMaster` to be able to update some parameters
    bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
    /// @notice Role for `PoolManager` only
    bytes32 public constant POOLMANAGER_ROLE = keccak256("POOLMANAGER_ROLE");

    // ============================== Modifiers ====================================

    /// @notice Checks if the person interacting with the perpetual with `perpetualID` is approved
    /// @param caller Address of the person seeking to interact with the perpetual
    /// @param perpetualID ID of the concerned perpetual
    /// @dev Generally in `PerpetualManager`, perpetual owners should store the ID of the perpetuals
    /// they are able to interact with
    modifier onlyApprovedOrOwner(address caller, uint256 perpetualID) {
        require(_isApprovedOrOwner(caller, perpetualID), "21");
        _;
    }

    /// @notice Checks if the message sender is the rewards distribution address
    modifier onlyRewardsDistribution() {
        require(msg.sender == rewardsDistribution, "1");
        _;
    }

    // =============================== Deployer ====================================

    /// @notice Notifies the address of the `_feeManager` and of the `oracle`
    /// to this contract and grants the correct roles
    /// @param governorList List of governor addresses of the protocol
    /// @param guardian Address of the guardian of the protocol
    /// @param feeManager_ Reference to the `FeeManager` contract which will be able to update fees
    /// @param oracle_ Reference to the `oracle` contract which will be able to update fees
    /// @dev Called by the `PoolManager` contract when it is activated by the `StableMaster`
    /// @dev The `governorList` and `guardian` here are those of the `Core` contract
    function deployCollateral(
        address[] memory governorList,
        address guardian,
        IFeeManager feeManager_,
        IOracle oracle_
    ) external override onlyRole(POOLMANAGER_ROLE) {
        for (uint256 i = 0; i < governorList.length; i++) {
            _grantRole(GUARDIAN_ROLE, governorList[i]);
        }
        // In the end guardian should be revoked by governance
        _grantRole(GUARDIAN_ROLE, guardian);
        _grantRole(GUARDIAN_ROLE, address(_stableMaster));
        _feeManager = feeManager_;
        oracle = oracle_;
    }

    // ========================== Rewards Distribution =============================

    /// @notice Notifies the contract that rewards are going to be shared among HAs of this pool
    /// @param reward Amount of governance tokens to be distributed to HAs
    /// @dev Only the reward distributor contract is allowed to call this function which starts a staking cycle
    /// @dev This function is the equivalent of the `notifyRewardAmount` function found in all staking contracts
    function notifyRewardAmount(uint256 reward) external override onlyRewardsDistribution {
        rewardPerTokenStored = _rewardPerToken();

        if (block.timestamp >= periodFinish) {
            // If the period is not done, then the reward rate changes
            rewardRate = reward / rewardsDuration;
        } else {
            uint256 remaining = periodFinish - block.timestamp;
            uint256 leftover = remaining * rewardRate;
            // If the period is not over, we compute the reward left and increase reward duration
            rewardRate = (reward + leftover) / rewardsDuration;
        }
        // Ensuring the provided reward amount is not more than the balance in the contract.
        // This keeps the reward rate in the right range, preventing overflows due to
        // very high values of `rewardRate` in the earned and `rewardsPerToken` functions;
        // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
        uint256 balance = rewardToken.balanceOf(address(this));

        require(rewardRate <= balance / rewardsDuration, "22");

        lastUpdateTime = block.timestamp;
        // Change the duration
        periodFinish = block.timestamp + rewardsDuration;
        emit RewardAdded(reward);
    }

    /// @notice Supports recovering LP Rewards from other systems such as BAL to be distributed to holders
    /// or tokens that were mistakenly
    /// @param tokenAddress Address of the token to transfer
    /// @param to Address to give tokens to
    /// @param tokenAmount Amount of tokens to transfer
    function recoverERC20(
        address tokenAddress,
        address to,
        uint256 tokenAmount
    ) external override onlyRewardsDistribution {
        require(tokenAddress != address(rewardToken), "20");
        IERC20(tokenAddress).safeTransfer(to, tokenAmount);
        emit Recovered(tokenAddress, to, tokenAmount);
    }

    /// @notice Changes the `rewardsDistribution` associated to this contract
    /// @param _rewardsDistribution Address of the new rewards distributor contract
    /// @dev This function is part of the staking rewards interface and it is used to propagate
    /// a change of rewards distributor notified by the current `rewardsDistribution` address
    /// @dev It has already been checked in the `RewardsDistributor` contract calling
    /// this function that the `newRewardsDistributor` had a compatible reward token
    /// @dev With this function, everything is as if `rewardsDistribution` was admin of its own role
    function setNewRewardsDistribution(address _rewardsDistribution) external override onlyRewardsDistribution {
        rewardsDistribution = _rewardsDistribution;
        emit RewardsDistributionUpdated(_rewardsDistribution);
    }

    // ================================= Keepers ===================================

    /// @notice Updates all the fees not depending on individual HA conditions via keeper utils functions
    /// @param feeDeposit New deposit global fees
    /// @param feeWithdraw New withdraw global fees
    /// @dev Governance may decide to incorporate a collateral ratio dependence in the fees for HAs,
    /// in this case it will be done through the `FeeManager` contract
    /// @dev This dependence can either be a bonus or a malus
    function setFeeKeeper(uint64 feeDeposit, uint64 feeWithdraw) external override {
        require(msg.sender == address(_feeManager), "1");
        haBonusMalusDeposit = feeDeposit;
        haBonusMalusWithdraw = feeWithdraw;
    }

    // ======== Governance - Guardian Functions - Staking and Pauses ===============

    /// @notice Pauses the `getReward` method as well as the functions allowing to open, modify or close perpetuals
    /// @dev After calling this function, it is going to be impossible for HAs to interact with their perpetuals
    /// or claim their rewards on it
    function pause() external override onlyRole(GUARDIAN_ROLE) {
        _pause();
    }

    /// @notice Unpauses HAs functions
    function unpause() external override onlyRole(GUARDIAN_ROLE) {
        _unpause();
    }

    /// @notice Sets the conditions and specifies the duration of the reward distribution
    /// @param _rewardsDuration Duration for the rewards for this contract
    /// @param _rewardsDistribution Address which will give the reward tokens
    /// @dev It allows governance to directly change the rewards distribution contract and the conditions
    /// at which this distribution is done
    /// @dev The compatibility of the reward token is not checked here: it is checked
    /// in the rewards distribution contract when activating this as a staking contract,
    /// so if a reward distributor is set here but does not have a compatible reward token, then this reward
    /// distributor will not be able to set this contract as a staking contract
    function setRewardDistribution(uint256 _rewardsDuration, address _rewardsDistribution)
        external
        onlyRole(GUARDIAN_ROLE)
        zeroCheck(_rewardsDistribution)
    {
        rewardsDuration = _rewardsDuration;
        rewardsDistribution = _rewardsDistribution;
        emit RewardsDistributionDurationUpdated(rewardsDuration, rewardsDistribution);
    }

    // ============ Governance - Guardian Functions - Parameters ===================

    /// @notice Sets `baseURI` that is the URI to access ERC721 metadata
    /// @param _baseURI New `baseURI` parameter
    function setBaseURI(string memory _baseURI) external onlyRole(GUARDIAN_ROLE) {
        baseURI = _baseURI;
        emit BaseURIUpdated(_baseURI);
    }

    /// @notice Sets `lockTime` that is the minimum amount of time HAs have to stay within the protocol
    /// @param _lockTime New `lockTime` parameter
    /// @dev This parameter is used to prevent HAs from exiting before a certain amount of time and taking advantage
    /// of insiders' information they may have due to oracle latency
    function setLockTime(uint64 _lockTime) external override onlyRole(GUARDIAN_ROLE) {
        lockTime = _lockTime;
        emit LockTimeUpdated(_lockTime);
    }

    /// @notice Changes the maximum leverage authorized (commit/margin) and the maintenance margin under which
    /// perpetuals can be liquidated
    /// @param _maxLeverage New value of the maximum leverage allowed
    /// @param _maintenanceMargin The new maintenance margin
    /// @dev For a perpetual, the leverage is defined as the ratio between the committed amount and the margin
    /// @dev For a perpetual, the maintenance margin is defined as the ratio between the margin ratio / the committed amount
    function setBoundsPerpetual(uint64 _maxLeverage, uint64 _maintenanceMargin)
        external
        override
        onlyRole(GUARDIAN_ROLE)
        onlyCompatibleFees(_maintenanceMargin)
    {
        // Checking the compatibility of the parameters
        require(BASE_PARAMS**2 > _maxLeverage * _maintenanceMargin, "8");
        maxLeverage = _maxLeverage;
        maintenanceMargin = _maintenanceMargin;
        emit BoundsPerpetualUpdated(_maxLeverage, _maintenanceMargin);
    }

    /// @notice Sets `xHAFees` that is the thresholds of values of the ratio between what's covered (hedged)
    /// divided by what's to hedge with HAs at which fees will change as well as
    /// `yHAFees` that is the value of the deposit or withdraw fees at threshold
    /// @param _xHAFees Array of the x-axis value for the fees (deposit or withdraw)
    /// @param _yHAFees Array of the y-axis value for the fees (deposit or withdraw)
    /// @param deposit Whether deposit or withdraw fees should be updated
    /// @dev Evolution of the fees is linear between two values of thresholds
    /// @dev These x values should be ranked in ascending order
    /// @dev For deposit fees, the higher the x that is the ratio between what's to hedge and what's hedged
    /// the higher y should be (the more expensive it should be for HAs to come in)
    /// @dev For withdraw fees, evolution should follow an opposite logic
    function setHAFees(
        uint64[] memory _xHAFees,
        uint64[] memory _yHAFees,
        uint8 deposit
    ) external override onlyRole(GUARDIAN_ROLE) onlyCompatibleInputArrays(_xHAFees, _yHAFees) {
        if (deposit == 1) {
            xHAFeesDeposit = _xHAFees;
            yHAFeesDeposit = _yHAFees;
        } else {
            xHAFeesWithdraw = _xHAFees;
            yHAFeesWithdraw = _yHAFees;
        }
        emit HAFeesUpdated(_xHAFees, _yHAFees, deposit);
    }

    /// @notice Sets the target and limit proportions of collateral from users that can be insured by HAs
    /// @param _targetHAHedge Proportion of collateral from users that HAs should hedge
    /// @param _limitHAHedge Proportion of collateral from users above which HAs can see their perpetuals
    /// cashed out
    /// @dev `targetHAHedge` equal to `BASE_PARAMS` means that all the collateral from users should be insured by HAs
    /// @dev `targetHAHedge` equal to 0 means HA should not cover (hedge) anything
    function setTargetAndLimitHAHedge(uint64 _targetHAHedge, uint64 _limitHAHedge)
        external
        override
        onlyRole(GUARDIAN_ROLE)
        onlyCompatibleFees(_targetHAHedge)
        onlyCompatibleFees(_limitHAHedge)
    {
        require(_targetHAHedge <= _limitHAHedge, "8");
        limitHAHedge = _limitHAHedge;
        targetHAHedge = _targetHAHedge;
        // Updating the value in the `stableMaster` contract
        _stableMaster.setTargetHAHedge(_targetHAHedge);
        emit TargetAndLimitHAHedgeUpdated(_targetHAHedge, _limitHAHedge);
    }

    /// @notice Sets the portion of the leftover cash out amount of liquidated perpetuals that go to keepers
    /// @param _keeperFeesLiquidationRatio Proportion to keepers
    /// @dev This proportion should be inferior to `BASE_PARAMS`
    function setKeeperFeesLiquidationRatio(uint64 _keeperFeesLiquidationRatio)
        external
        override
        onlyRole(GUARDIAN_ROLE)
        onlyCompatibleFees(_keeperFeesLiquidationRatio)
    {
        keeperFeesLiquidationRatio = _keeperFeesLiquidationRatio;
        emit KeeperFeesLiquidationRatioUpdated(keeperFeesLiquidationRatio);
    }

    /// @notice Sets the maximum amounts going to the keepers when closing perpetuals
    /// because too much was hedged by HAs or when liquidating a perpetual
    /// @param _keeperFeesLiquidationCap Maximum reward going to the keeper liquidating a perpetual
    /// @param _keeperFeesClosingCap Maximum reward going to the keeper forcing the closing of an ensemble
    /// of perpetuals
    function setKeeperFeesCap(uint256 _keeperFeesLiquidationCap, uint256 _keeperFeesClosingCap)
        external
        override
        onlyRole(GUARDIAN_ROLE)
    {
        keeperFeesLiquidationCap = _keeperFeesLiquidationCap;
        keeperFeesClosingCap = _keeperFeesClosingCap;
        emit KeeperFeesCapUpdated(keeperFeesLiquidationCap, keeperFeesClosingCap);
    }

    /// @notice Sets the x-array (ie thresholds) for `FeeManager` when closing perpetuals and the y-array that is the
    /// value of the proportions of the fees going to keepers closing perpetuals
    /// @param _xKeeperFeesClosing Thresholds for closing fees
    /// @param _yKeeperFeesClosing Value of the fees at the different threshold values specified in `xKeeperFeesClosing`
    /// @dev The x thresholds correspond to values of the hedge ratio divided by two
    /// @dev `xKeeperFeesClosing` and `yKeeperFeesClosing` should have the same length
    function setKeeperFeesClosing(uint64[] memory _xKeeperFeesClosing, uint64[] memory _yKeeperFeesClosing)
        external
        override
        onlyRole(GUARDIAN_ROLE)
        onlyCompatibleInputArrays(_xKeeperFeesClosing, _yKeeperFeesClosing)
    {
        xKeeperFeesClosing = _xKeeperFeesClosing;
        yKeeperFeesClosing = _yKeeperFeesClosing;
        emit KeeperFeesClosingUpdated(xKeeperFeesClosing, yKeeperFeesClosing);
    }

    // ================ Governance - `PoolManager` Functions =======================

    /// @notice Changes the reference to the `FeeManager` contract
    /// @param feeManager_ New `FeeManager` contract
    /// @dev This allows the `PoolManager` contract to propagate changes to the `PerpetualManager`
    /// @dev This is the only place where the `_feeManager` can be changed, it is as if there was
    /// a `FEEMANAGER_ROLE` for which `PoolManager` was the admin
    function setFeeManager(IFeeManager feeManager_) external override onlyRole(POOLMANAGER_ROLE) {
        _feeManager = feeManager_;
    }

    // ======================= `StableMaster` Function =============================

    /// @notice Changes the oracle contract used to compute collateral price with respect to the stablecoin's price
    /// @param oracle_ Oracle contract
    /// @dev The collateral `PoolManager` does not store a reference to an oracle, the value of the oracle
    /// is hence directly set by the `StableMaster`
    function setOracle(IOracle oracle_) external override {
        require(msg.sender == address(_stableMaster), "1");
        oracle = oracle_;
    }
}


// File contracts/perpetualManager/PerpetualManagerFront.sol



pragma solidity ^0.8.7;

/// @title PerpetualManagerFront
/// @author Angle Core Team
/// @notice `PerpetualManager` is the contract handling all the Hedging Agents perpetuals
/// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol
/// @dev This file contains the functions of the `PerpetualManager` that can be directly interacted
/// with by external agents. These functions are the ones that need to be called to open, modify or close
/// perpetuals
/// @dev `PerpetualManager` naturally handles staking, the code allowing HAs to stake has been inspired from
/// https://github.com/SetProtocol/index-coop-contracts/blob/master/contracts/staking/StakingRewardsV2.sol
/// @dev Perpetuals at Angle protocol are treated as NFTs, this contract handles the logic for that
contract PerpetualManagerFront is PerpetualManager, IPerpetualManagerFront {
    using SafeERC20 for IERC20;
    using CountersUpgradeable for CountersUpgradeable.Counter;

    // =============================== Deployer ====================================

    /// @notice Initializes the `PerpetualManager` contract
    /// @param poolManager_ Reference to the `PoolManager` contract handling the collateral associated to the `PerpetualManager`
    /// @param rewardToken_ Reference to the `rewardtoken` that can be distributed to HAs as they have open positions
    /// @dev The reward token is most likely going to be the ANGLE token
    /// @dev Since this contract is upgradeable, this function is an `initialize` and not a `constructor`
    /// @dev Zero checks are only performed on addresses for which no external calls are made, in this case just
    /// the `rewardToken_` is checked
    /// @dev After initializing this contract, all the fee parameters should be initialized by governance using
    /// the setters in this contract
    function initialize(IPoolManager poolManager_, IERC20 rewardToken_)
        external
        initializer
        zeroCheck(address(rewardToken_))
    {
        // Initializing contracts
        __Pausable_init();
        __AccessControl_init();

        // Creating references
        poolManager = poolManager_;
        _token = IERC20(poolManager_.token());
        _stableMaster = IStableMaster(poolManager_.stableMaster());
        rewardToken = rewardToken_;
        _collatBase = 10**(IERC20Metadata(address(_token)).decimals());
        // The references to the `feeManager` and to the `oracle` contracts are to be set when the contract is deployed

        // Setting up Access Control for this contract
        // There is no need to store the reference to the `PoolManager` address here
        // Once the `POOLMANAGER_ROLE` has been granted, no new addresses can be granted or revoked
        // from this role: a `PerpetualManager` contract can only have one `PoolManager` associated
        _setupRole(POOLMANAGER_ROLE, address(poolManager));
        // `PoolManager` is admin of all the roles. Most of the time, changes are propagated from it
        _setRoleAdmin(GUARDIAN_ROLE, POOLMANAGER_ROLE);
        _setRoleAdmin(POOLMANAGER_ROLE, POOLMANAGER_ROLE);
        // Pausing the contract because it is not functional till the collateral has really been deployed by the
        // `StableMaster`
        _pause();
    }

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() initializer {}

    // ================================= HAs =======================================

    /// @notice Lets a HA join the protocol and create a perpetual
    /// @param owner Address of the future owner of the perpetual
    /// @param margin Amount of collateral brought by the HA
    /// @param committedAmount Amount of collateral covered by the HA
    /// @param maxOracleRate Maximum oracle value that the HA wants to see stored in the perpetual
    /// @param minNetMargin Minimum net margin that the HA is willing to see stored in the perpetual
    /// @return perpetualID The ID of the perpetual opened by this HA
    /// @dev The future owner of the perpetual cannot be the zero address
    /// @dev It is possible to open a perpetual on behalf of someone else
    /// @dev The `maxOracleRate` parameter serves as a protection against oracle manipulations for HAs opening perpetuals
    /// @dev `minNetMargin` is a protection against too big variations in the fees for HAs
    function openPerpetual(
        address owner,
        uint256 margin,
        uint256 committedAmount,
        uint256 maxOracleRate,
        uint256 minNetMargin
    ) external override whenNotPaused zeroCheck(owner) returns (uint256 perpetualID) {
        // Transaction will revert anyway if `margin` is zero
        require(committedAmount > 0, "27");

        // There could be a reentrancy attack as a call to an external contract is done before state variables
        // updates. Yet in this case, the call involves a transfer from the `msg.sender` to the contract which
        // eliminates the risk
        _token.safeTransferFrom(msg.sender, address(poolManager), margin);

        // Computing the oracle value
        // Only the highest oracle value (between Chainlink and Uniswap) we get is stored in the perpetual
        (, uint256 rateUp) = _getOraclePrice();
        // Checking if the oracle rate is not too big: a too big oracle rate could mean for a HA that the price
        // has become too high to make it interesting to open a perpetual
        require(rateUp <= maxOracleRate, "28");

        // Computing the total amount of stablecoins that this perpetual is going to hedge for the protocol
        uint256 totalHedgeAmountUpdate = (committedAmount * rateUp) / _collatBase;
        // Computing the net amount brought by the HAs to store in the perpetual
        uint256 netMargin = _getNetMargin(margin, totalHedgeAmountUpdate, committedAmount);
        require(netMargin >= minNetMargin, "29");
        // Checking if the perpetual is not too leveraged, even after computing the fees
        require((committedAmount * BASE_PARAMS) <= maxLeverage * netMargin, "30");

        // ERC721 logic
        _perpetualIDcount.increment();
        perpetualID = _perpetualIDcount.current();

        // In the logic of the staking contract, the `_updateReward` should be called
        // before the perpetual is opened
        _updateReward(perpetualID, 0);

        // Updating the total amount of stablecoins hedged by HAs and creating the perpetual
        totalHedgeAmount += totalHedgeAmountUpdate;

        perpetualData[perpetualID] = Perpetual(rateUp, block.timestamp, netMargin, committedAmount);

        // Following ERC721 logic, the function `_mint(...)` calls `_checkOnERC721Received` and could then be used as
        // a reentrancy vector. Minting should then only be done at the very end after updating all variables.
        _mint(owner, perpetualID);
        emit PerpetualOpened(perpetualID, rateUp, netMargin, committedAmount);
    }

    /// @notice Lets a HA close a perpetual owned or controlled for the stablecoin/collateral pair associated
    /// to this `PerpetualManager` contract
    /// @param perpetualID ID of the perpetual to close
    /// @param to Address which will receive the proceeds from this perpetual
    /// @param minCashOutAmount Minimum net cash out amount that the HA is willing to get for closing the
    /// perpetual
    /// @dev The HA gets the current amount of her position depending on the entry oracle value
    /// and current oracle value minus some transaction fees computed on the committed amount
    /// @dev `msg.sender` should be the owner of `perpetualID` or be approved for this perpetual
    /// @dev If the `PoolManager` does not have enough collateral, the perpetual owner will be converted to a SLP and
    /// receive sanTokens
    /// @dev The `minCashOutAmount` serves as a protection for HAs closing their perpetuals: it protects them both
    /// from fees that would have become too high and from a too big decrease in oracle value
    function closePerpetual(
        uint256 perpetualID,
        address to,
        uint256 minCashOutAmount
    ) external override whenNotPaused onlyApprovedOrOwner(msg.sender, perpetualID) {
        // Loading perpetual data and getting the oracle price
        Perpetual memory perpetual = perpetualData[perpetualID];
        (uint256 rateDown, ) = _getOraclePrice();
        // The lowest oracle price between Chainlink and Uniswap is used to compute the perpetual's position at
        // the time of closing: it is the one that is most at the advantage of the protocol
        (uint256 cashOutAmount, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown);
        if (liquidated == 0) {
            // You need to wait `lockTime` before being able to withdraw funds from the protocol as a HA
            require(perpetual.entryTimestamp + lockTime <= block.timestamp, "31");
            // Cashing out the perpetual internally
            _closePerpetual(perpetualID, perpetual);
            // Computing exit fees: they depend on how much is already hedgeded by HAs compared with what's to hedge
            (uint256 netCashOutAmount, ) = _getNetCashOutAmount(
                cashOutAmount,
                perpetual.committedAmount,
                // The perpetual has already been cashed out when calling this function, so there is no
                // `committedAmount` to add to the `totalHedgeAmount` to get the `currentHedgeAmount`
                _computeHedgeRatio(totalHedgeAmount)
            );
            require(netCashOutAmount >= minCashOutAmount, "32");
            emit PerpetualClosed(perpetualID, netCashOutAmount);
            _secureTransfer(to, netCashOutAmount);
        }
    }

    /// @notice Lets a HA increase the `margin` in a perpetual she controls for this
    /// stablecoin/collateral pair
    /// @param perpetualID ID of the perpetual to which amount should be added to `margin`
    /// @param amount Amount to add to the perpetual's `margin`
    /// @dev This decreases the leverage multiple of this perpetual
    /// @dev If this perpetual is to be liquidated, the HA is not going to be able to add liquidity to it
    /// @dev Since this function can be used to add liquidity to a perpetual, there is no need to restrict
    /// it to the owner of the perpetual
    /// @dev Calling this function on a non-existing perpetual makes it revert
    function addToPerpetual(uint256 perpetualID, uint256 amount) external override whenNotPaused {
        // Loading perpetual data and getting the oracle price
        Perpetual memory perpetual = perpetualData[perpetualID];
        (uint256 rateDown, ) = _getOraclePrice();
        (, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown);
        if (liquidated == 0) {
            // Overflow check
            _token.safeTransferFrom(msg.sender, address(poolManager), amount);
            perpetualData[perpetualID].margin += amount;
            emit PerpetualUpdated(perpetualID, perpetual.margin + amount);
        }
    }

    /// @notice Lets a HA decrease the `margin` in a perpetual she controls for this
    /// stablecoin/collateral pair
    /// @param perpetualID ID of the perpetual from which collateral should be removed
    /// @param amount Amount to remove from the perpetual's `margin`
    /// @param to Address which will receive the collateral removed from this perpetual
    /// @dev This increases the leverage multiple of this perpetual
    /// @dev `msg.sender` should be the owner of `perpetualID` or be approved for this perpetual
    function removeFromPerpetual(
        uint256 perpetualID,
        uint256 amount,
        address to
    ) external override whenNotPaused onlyApprovedOrOwner(msg.sender, perpetualID) {
        // Loading perpetual data and getting the oracle price
        Perpetual memory perpetual = perpetualData[perpetualID];
        (uint256 rateDown, ) = _getOraclePrice();

        (uint256 cashOutAmount, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown);
        if (liquidated == 0) {
            // Checking if money can be withdrawn from the perpetual
            require(
                // The perpetual should not have been opened too soon
                (perpetual.entryTimestamp + lockTime <= block.timestamp) &&
                    // The amount to withdraw should not be more important than the perpetual's `cashOutAmount` and `margin`
                    (amount < cashOutAmount) &&
                    (amount < perpetual.margin) &&
                    // Withdrawing collateral should not make the leverage of the perpetual too important
                    // Checking both on `cashOutAmount` and `perpetual.margin` (as we can have either
                    // `cashOutAmount >= perpetual.margin` or `cashOutAmount<perpetual.margin`)
                    // No checks are done on `maintenanceMargin`, as conditions on `maxLeverage` are more restrictive
                    perpetual.committedAmount * BASE_PARAMS <= (cashOutAmount - amount) * maxLeverage &&
                    perpetual.committedAmount * BASE_PARAMS <= (perpetual.margin - amount) * maxLeverage,
                "33"
            );
            perpetualData[perpetualID].margin -= amount;
            emit PerpetualUpdated(perpetualID, perpetual.margin - amount);

            _secureTransfer(to, amount);
        }
    }

    /// @notice Allows an outside caller to liquidate perpetuals if their margin ratio is
    /// under the maintenance margin
    /// @param perpetualIDs ID of the targeted perpetuals
    /// @dev Liquidation of a perpetual will succeed if the `cashOutAmount` of the perpetual is under the maintenance margin,
    /// and nothing will happen if the perpetual is still healthy
    /// @dev The outside caller (namely a keeper) gets a portion of the leftover cash out amount of the perpetual
    /// @dev As keepers may directly profit from this function, there may be front-running problems with miners bots,
    /// we may have to put an access control logic for this function to only allow white-listed addresses to act
    /// as keepers for the protocol
    function liquidatePerpetuals(uint256[] memory perpetualIDs) external override whenNotPaused {
        // Getting the oracle price
        (uint256 rateDown, ) = _getOraclePrice();
        uint256 liquidationFees;
        for (uint256 i = 0; i < perpetualIDs.length; i++) {
            uint256 perpetualID = perpetualIDs[i];
            if (_exists(perpetualID)) {
                // Loading perpetual data
                Perpetual memory perpetual = perpetualData[perpetualID];
                (uint256 cashOutAmount, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown);
                if (liquidated == 1) {
                    // Computing the incentive for the keeper as a function of the `cashOutAmount` of the perpetual
                    // This incentivizes keepers to react fast when the price starts to go below the liquidation
                    // margin
                    liquidationFees += _computeKeeperLiquidationFees(cashOutAmount);
                }
            }
        }
        emit KeeperTransferred(msg.sender, liquidationFees);
        _secureTransfer(msg.sender, liquidationFees);
    }

    /// @notice Allows an outside caller to close perpetuals if too much of the collateral from
    /// users is hedged by HAs
    /// @param perpetualIDs IDs of the targeted perpetuals
    /// @dev This function allows to make sure that the protocol will not have too much HAs for a long period of time
    /// @dev A HA that owns a targeted perpetual will get the current value of her perpetual
    /// @dev The call to the function above will revert if HAs cannot be cashed out
    /// @dev As keepers may directly profit from this function, there may be front-running problems with miners bots,
    /// we may have to put an access control logic for this function to only allow white-listed addresses to act
    /// as keepers for the protocol
    function forceClosePerpetuals(uint256[] memory perpetualIDs) external override whenNotPaused {
        // Getting the oracle prices
        // `rateUp` is used to compute the cost of manipulation of the covered amounts
        (uint256 rateDown, uint256 rateUp) = _getOraclePrice();

        // Fetching `stocksUsers` to check if perpetuals cover too much collateral
        uint256 stocksUsers = _stableMaster.getStocksUsers();
        uint256 targetHedgeAmount = (stocksUsers * targetHAHedge) / BASE_PARAMS;

        // `totalHedgeAmount` should be greater than the limit hedge amount
        require(totalHedgeAmount > (stocksUsers * limitHAHedge) / BASE_PARAMS, "34");
        uint256 liquidationFees;
        uint256 cashOutFees;

        // Array of pairs `(owner, netCashOutAmount)`
        Pairs[] memory outputPairs = new Pairs[](perpetualIDs.length);

        for (uint256 i = 0; i < perpetualIDs.length; i++) {
            uint256 perpetualID = perpetualIDs[i];
            address owner = _owners[perpetualID];
            if (owner != address(0)) {
                // Loading perpetual data and getting the oracle price
                Perpetual memory perpetual = perpetualData[perpetualID];
                // First checking if the perpetual should not be liquidated
                (uint256 cashOutAmount, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown);
                if (liquidated == 1) {
                    // This results in the perpetual being liquidated and the keeper being paid the same amount of fees as
                    // what would have been paid if the perpetual had been liquidated using the `liquidatePerpetualFunction`
                    // Computing the incentive for the keeper as a function of the `cashOutAmount` of the perpetual
                    // This incentivizes keepers to react fast
                    liquidationFees += _computeKeeperLiquidationFees(cashOutAmount);
                } else if (perpetual.entryTimestamp + lockTime <= block.timestamp) {
                    // It is impossible to force the closing a perpetual that was just created: in the other case, this
                    // function could be used to do some insider trading and to bypass the `lockTime` limit
                    // If too much collateral is hedged by HAs, then the perpetual can be cashed out
                    _closePerpetual(perpetualID, perpetual);
                    uint64 ratioPostCashOut;
                    // In this situation, `totalHedgeAmount` is the `currentHedgeAmount`
                    if (targetHedgeAmount > totalHedgeAmount) {
                        ratioPostCashOut = uint64((totalHedgeAmount * BASE_PARAMS) / targetHedgeAmount);
                    } else {
                        ratioPostCashOut = uint64(BASE_PARAMS);
                    }
                    // Computing how much the HA will get and the amount of fees paid at closing
                    (uint256 netCashOutAmount, uint256 fees) = _getNetCashOutAmount(
                        cashOutAmount,
                        perpetual.committedAmount,
                        ratioPostCashOut
                    );
                    cashOutFees += fees;
                    // Storing the owners of perpetuals that were forced cash out in a memory array to avoid
                    // reentrancy attacks
                    outputPairs[i] = Pairs(owner, netCashOutAmount);
                }

                // Checking if at this point enough perpetuals have been cashed out
                if (totalHedgeAmount <= targetHedgeAmount) break;
            }
        }

        uint64 ratio = (targetHedgeAmount == 0)
            ? 0
            : uint64((totalHedgeAmount * BASE_PARAMS) / (2 * targetHedgeAmount));
        // Computing the rewards given to the keeper calling this function
        // and transferring the rewards to the keeper
        // Using a cache value of `cashOutFees` to save some gas
        // The value below is the amount of fees that should go to the keeper forcing the closing of perpetuals
        // In the linear by part function, if `xKeeperFeesClosing` is greater than 0.5 (meaning we are not at target yet)
        // then keepers should get almost no fees
        cashOutFees = (cashOutFees * _piecewiseLinear(ratio, xKeeperFeesClosing, yKeeperFeesClosing)) / BASE_PARAMS;
        // The amount of fees that can go to keepers is capped by a parameter set by governance
        cashOutFees = cashOutFees < keeperFeesClosingCap ? cashOutFees : keeperFeesClosingCap;
        // A malicious attacker could take advantage of this function to take a flash loan, burn agTokens
        // to diminish the stocks users and then force close some perpetuals. We also need to check that assuming
        // really small burn transaction fees (of 0.05%), an attacker could make a profit with such flash loan
        // if current hedge is below the target hedge by making such flash loan.
        // The formula for the cost of such flash loan is:
        // `fees * (limitHAHedge - targetHAHedge) * stocksUsers / oracle`
        // In order to avoid doing multiplications after divisions, and to get everything in the correct base, we do:
        uint256 estimatedCost = (5 * (limitHAHedge - targetHAHedge) * stocksUsers * _collatBase) /
            (rateUp * 10000 * BASE_PARAMS);
        cashOutFees = cashOutFees < estimatedCost ? cashOutFees : estimatedCost;

        emit PerpetualsForceClosed(perpetualIDs, outputPairs, msg.sender, cashOutFees + liquidationFees);

        // Processing transfers after all calculations have been performed
        for (uint256 j = 0; j < perpetualIDs.length; j++) {
            if (outputPairs[j].netCashOutAmount > 0) {
                _secureTransfer(outputPairs[j].owner, outputPairs[j].netCashOutAmount);
            }
        }
        _secureTransfer(msg.sender, cashOutFees + liquidationFees);
    }

    // =========================== External View Function ==========================

    /// @notice Returns the `cashOutAmount` of the perpetual owned by someone at a given oracle value
    /// @param perpetualID ID of the perpetual
    /// @param rate Oracle value
    /// @return The `cashOutAmount` of the perpetual
    /// @return Whether the position of the perpetual is now too small compared with its initial position and should hence
    /// be liquidated
    /// @dev This function is used by the Collateral Settlement contract
    function getCashOutAmount(uint256 perpetualID, uint256 rate) external view override returns (uint256, uint256) {
        Perpetual memory perpetual = perpetualData[perpetualID];
        return _getCashOutAmount(perpetual, rate);
    }

    // =========================== Reward Distribution =============================

    /// @notice Allows to check the amount of reward tokens earned by a perpetual
    /// @param perpetualID ID of the perpetual to check
    function earned(uint256 perpetualID) external view returns (uint256) {
        return _earned(perpetualID, perpetualData[perpetualID].committedAmount * perpetualData[perpetualID].entryRate);
    }

    /// @notice Allows a perpetual owner to withdraw rewards
    /// @param perpetualID ID of the perpetual which accumulated tokens
    /// @dev Only an approved caller can claim the rewards for the perpetual with perpetualID
    function getReward(uint256 perpetualID) external whenNotPaused onlyApprovedOrOwner(msg.sender, perpetualID) {
        _getReward(perpetualID, perpetualData[perpetualID].committedAmount * perpetualData[perpetualID].entryRate);
    }

    // =============================== ERC721 logic ================================

    /// @notice Gets the name of the NFT collection implemented by this contract
    function name() external pure override returns (string memory) {
        return "AnglePerp";
    }

    /// @notice Gets the symbol of the NFT collection implemented by this contract
    function symbol() external pure override returns (string memory) {
        return "AnglePerp";
    }

    /// @notice Gets the URI containing metadata
    /// @param perpetualID ID of the perpetual
    function tokenURI(uint256 perpetualID) external view override returns (string memory) {
        require(_exists(perpetualID), "2");
        // There is no perpetual with `perpetualID` equal to 0, so the following variable is
        // always greater than zero
        uint256 temp = perpetualID;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (perpetualID != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(perpetualID % 10)));
            perpetualID /= 10;
        }
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, string(buffer))) : "";
    }

    /// @notice Gets the balance of an owner
    /// @param owner Address of the owner
    /// @dev Balance here represents the number of perpetuals owned by a HA
    function balanceOf(address owner) external view override returns (uint256) {
        require(owner != address(0), "0");
        return _balances[owner];
    }

    /// @notice Gets the owner of the perpetual with ID perpetualID
    /// @param perpetualID ID of the perpetual
    function ownerOf(uint256 perpetualID) external view override returns (address) {
        return _ownerOf(perpetualID);
    }

    /// @notice Approves to an address specified by `to` a perpetual specified by `perpetualID`
    /// @param to Address to approve the perpetual to
    /// @param perpetualID ID of the perpetual
    /// @dev The approved address will have the right to transfer the perpetual, to cash it out
    /// on behalf of the owner, to add or remove collateral in it and to choose the destination
    /// address that will be able to receive the proceeds of the perpetual
    function approve(address to, uint256 perpetualID) external override {
        address owner = _ownerOf(perpetualID);
        require(to != owner, "35");
        require(msg.sender == owner || isApprovedForAll(owner, msg.sender), "21");

        _approve(to, perpetualID);
    }

    /// @notice Gets the approved address by a perpetual owner
    /// @param perpetualID ID of the concerned perpetual
    function getApproved(uint256 perpetualID) external view override returns (address) {
        require(_exists(perpetualID), "2");
        return _getApproved(perpetualID);
    }

    /// @notice Sets approval on all perpetuals owned by the owner to an operator
    /// @param operator Address to approve (or block) on all perpetuals
    /// @param approved Whether the sender wants to approve or block the operator
    function setApprovalForAll(address operator, bool approved) external override {
        require(operator != msg.sender, "36");
        _operatorApprovals[msg.sender][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

    /// @notice Gets if the operator address is approved on all perpetuals by the owner
    /// @param owner Owner of perpetuals
    /// @param operator Address to check if approved
    function isApprovedForAll(address owner, address operator) public view override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /// @notice Gets if the sender address is approved for the perpetualId
    /// @param perpetualID ID of the perpetual
    function isApprovedOrOwner(address spender, uint256 perpetualID) external view override returns (bool) {
        return _isApprovedOrOwner(spender, perpetualID);
    }

    /// @notice Transfers the `perpetualID` from an address to another
    /// @param from Source address
    /// @param to Destination a address
    /// @param perpetualID ID of the perpetual to transfer
    function transferFrom(
        address from,
        address to,
        uint256 perpetualID
    ) external override onlyApprovedOrOwner(msg.sender, perpetualID) {
        _transfer(from, to, perpetualID);
    }

    /// @notice Safely transfers the `perpetualID` from an address to another without data in it
    /// @param from Source address
    /// @param to Destination a address
    /// @param perpetualID ID of the perpetual to transfer
    function safeTransferFrom(
        address from,
        address to,
        uint256 perpetualID
    ) external override {
        safeTransferFrom(from, to, perpetualID, "");
    }

    /// @notice Safely transfers the `perpetualID` from an address to another with data in the transfer
    /// @param from Source address
    /// @param to Destination a address
    /// @param perpetualID ID of the perpetual to transfer
    function safeTransferFrom(
        address from,
        address to,
        uint256 perpetualID,
        bytes memory _data
    ) public override onlyApprovedOrOwner(msg.sender, perpetualID) {
        _safeTransfer(from, to, perpetualID, _data);
    }

    // =============================== ERC165 logic ================================

    /// @notice Queries if a contract implements an interface
    /// @param interfaceId The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function uses less than 30,000 gas.
    /// Required by the ERC721 standard, so used to check that the IERC721 is implemented.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceId) external pure override(IERC165) returns (bool) {
        return
            interfaceId == type(IPerpetualManagerFront).interfaceId ||
            interfaceId == type(IPerpetualManagerFunctions).interfaceId ||
            interfaceId == type(IStakingRewards).interfaceId ||
            interfaceId == type(IStakingRewardsFunctions).interfaceId ||
            interfaceId == type(IAccessControl).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC165).interfaceId;
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_baseURI","type":"string"}],"name":"BaseURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_maxLeverage","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"_maintenanceMargin","type":"uint64"}],"name":"BoundsPerpetualUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64[]","name":"_xHAFees","type":"uint64[]"},{"indexed":false,"internalType":"uint64[]","name":"_yHAFees","type":"uint64[]"},{"indexed":false,"internalType":"uint8","name":"deposit","type":"uint8"}],"name":"HAFeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_keeperFeesLiquidationCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_keeperFeesClosingCap","type":"uint256"}],"name":"KeeperFeesCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64[]","name":"xKeeperFeesClosing","type":"uint64[]"},{"indexed":false,"internalType":"uint64[]","name":"yKeeperFeesClosing","type":"uint64[]"}],"name":"KeeperFeesClosingUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_keeperFeesLiquidationRatio","type":"uint64"}],"name":"KeeperFeesLiquidationRatioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"keeperAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidationFees","type":"uint256"}],"name":"KeeperTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_lockTime","type":"uint64"}],"name":"LockTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_perpetualID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_closeAmount","type":"uint256"}],"name":"PerpetualClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_perpetualID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_entryRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_committedAmount","type":"uint256"}],"name":"PerpetualOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_perpetualID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_margin","type":"uint256"}],"name":"PerpetualUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"perpetualIDs","type":"uint256[]"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"netCashOutAmount","type":"uint256"}],"indexed":false,"internalType":"struct Pairs[]","name":"ownerAndCashOut","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"keeper","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"PerpetualsForceClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_rewardsDuration","type":"uint256"},{"indexed":true,"internalType":"address","name":"_rewardsDistributor","type":"address"}],"name":"RewardsDistributionDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_rewardsDistributor","type":"address"}],"name":"RewardsDistributionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_targetHAHedge","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"_limitHAHedge","type":"uint64"}],"name":"TargetAndLimitHAHedgeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"BASE_PARAMS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOLMANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addToPerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minCashOutAmount","type":"uint256"}],"name":"closePerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"governorList","type":"address[]"},{"internalType":"address","name":"guardian","type":"address"},{"internalType":"contract IFeeManager","name":"feeManager_","type":"address"},{"internalType":"contract IOracle","name":"oracle_","type":"address"}],"name":"deployCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"perpetualIDs","type":"uint256[]"}],"name":"forceClosePerpetuals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"getCashOutAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"haBonusMalusDeposit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"haBonusMalusWithdraw","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IPoolManager","name":"poolManager_","type":"address"},{"internalType":"contract IERC20","name":"rewardToken_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"isApprovedOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeperFeesClosingCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeperFeesLiquidationCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeperFeesLiquidationRatio","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limitHAHedge","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"perpetualIDs","type":"uint256[]"}],"name":"liquidatePerpetuals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maintenanceMargin","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLeverage","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"committedAmount","type":"uint256"},{"internalType":"uint256","name":"maxOracleRate","type":"uint256"},{"internalType":"uint256","name":"minNetMargin","type":"uint256"}],"name":"openPerpetual","outputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"perpetualData","outputs":[{"internalType":"uint256","name":"entryRate","type":"uint256"},{"internalType":"uint256","name":"entryTimestamp","type":"uint256"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"committedAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"perpetualRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolManager","outputs":[{"internalType":"contract IPoolManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"removeFromPerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDistribution","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_maxLeverage","type":"uint64"},{"internalType":"uint64","name":"_maintenanceMargin","type":"uint64"}],"name":"setBoundsPerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"feeDeposit","type":"uint64"},{"internalType":"uint64","name":"feeWithdraw","type":"uint64"}],"name":"setFeeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFeeManager","name":"feeManager_","type":"address"}],"name":"setFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"_xHAFees","type":"uint64[]"},{"internalType":"uint64[]","name":"_yHAFees","type":"uint64[]"},{"internalType":"uint8","name":"deposit","type":"uint8"}],"name":"setHAFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keeperFeesLiquidationCap","type":"uint256"},{"internalType":"uint256","name":"_keeperFeesClosingCap","type":"uint256"}],"name":"setKeeperFeesCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"_xKeeperFeesClosing","type":"uint64[]"},{"internalType":"uint64[]","name":"_yKeeperFeesClosing","type":"uint64[]"}],"name":"setKeeperFeesClosing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_keeperFeesLiquidationRatio","type":"uint64"}],"name":"setKeeperFeesLiquidationRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_lockTime","type":"uint64"}],"name":"setLockTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsDistribution","type":"address"}],"name":"setNewRewardsDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracle","name":"oracle_","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsDuration","type":"uint256"},{"internalType":"address","name":"_rewardsDistribution","type":"address"}],"name":"setRewardDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_targetHAHedge","type":"uint64"},{"internalType":"uint64","name":"_limitHAHedge","type":"uint64"}],"name":"setTargetAndLimitHAHedge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"targetHAHedge","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalHedgeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xHAFeesDeposit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xHAFeesWithdraw","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xKeeperFeesClosing","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"yHAFeesDeposit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"yHAFeesWithdraw","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"yKeeperFeesClosing","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b50602154610100900460ff16806200002c575060215460ff16155b620000945760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b602154610100900460ff16158015620000b7576021805461ffff19166101011790555b8015620000ca576021805461ff00191690555b50615fff80620000db6000396000f3fe608060405234801561001057600080fd5b50600436106104a15760003560e01c80637bd06a151161026d578063c0212c7211610151578063df136d65116100ce578063e985e9c511610092578063e985e9c514610aba578063ebe2b12b14610af4578063f301af4214610afd578063f5d011c514610b1d578063f7c618c114610b30578063f902fad714610b4357600080fd5b8063df136d6514610a54578063df1b8bd314610a5d578063e048684214610a6c578063e2b01a5e14610a94578063e5234c7a14610aa757600080fd5b8063d1aace9f11610115578063d1aace9f146109f5578063d547741f14610a08578063d5eb058114610a1b578063d7f6328e14610a2e578063dc4c90d314610a4157600080fd5b8063c0212c72146109a0578063c1618dda146109b3578063c628a6f7146109c6578063c87b56dd146109d9578063c8f33c91146109ec57600080fd5b806395d89b41116101ea578063ae3302c2116101ae578063ae3302c214610931578063b126e7e51461094b578063b3b1cb271461095e578063b88d4fde14610971578063b8f3689514610984578063bcb01a801461098d57600080fd5b806395d89b41146104ce5780639f48118f146108f8578063a217fddf14610903578063a22cb4651461090b578063a62b2a3d1461091e57600080fd5b8063873291bb11610231578063873291bb1461086f5780638c6dfaf7146108825780638d5e19f11461088b5780638e240144146108a557806391d14854146108bf57600080fd5b80637bd06a15146108185780637dc0d1d0146108215780638211477a14610834578063840a7698146108475780638456cb591461086757600080fd5b8063386a9525116103945780634d6ed8c4116103115780636c0360eb116102d55780636c0360eb146107bb5780636d59dae7146107c357806370a08231146107d65780637adbf973146107e95780637b0a47ee146107fc5780637b39ecf71461080557600080fd5b80634d6ed8c414610764578063515dc4801461077757806355f804b31461078a5780635c975abb1461079d5780636352211e146107a857600080fd5b8063430c208111610358578063430c208114610705578063472d35b91461071857806347c12e011461072b578063485cc9551461073e57806349a5d3ef1461075157600080fd5b8063386a9525146106bb5780633c6b16ab146106c45780633f4ba83a146106d75780633fc6df6e146106df57806342842e0e146106f257600080fd5b806323b872dd11610422578063324f3815116103e6578063324f38151461065557806336568abe1461066f5780633675441514610682578063367f21b41461069557806338050129146106a857600080fd5b806323b872dd146105e4578063248a9ca3146105f757806324d83b791461061a57806324ea54f41461062d5780632f2ff15d1461064257600080fd5b80630c016dc0116104695780630c016dc01461056e5780630d668087146105915780631171bda9146105ab578063142c3ba0146105be5780631c4b774b146105d157600080fd5b806301ffc9a7146104a657806306fdde03146104ce578063081812fc146104fc578063095ea7b3146105275780630bfab8a71461053c575b600080fd5b6104b96104b43660046155ba565b610b98565b60405190151581526020015b60405180910390f35b6040805180820190915260098152680416e676c65506572760bc1b60208201525b6040516104c59190615b3d565b61050f61050a36600461557c565b610c71565b6040516001600160a01b0390911681526020016104c5565b61053a6105353660046152ab565b610cdb565b005b600e5461055690600160c01b90046001600160401b031681565b6040516001600160401b0390911681526020016104c5565b610583600080516020615f8a83398151915281565b6040519081526020016104c5565b600e5461055690600160801b90046001600160401b031681565b61053a6105b93660046151bd565b610d92565b6105566105cc36600461557c565b610e65565b61053a6105df36600461557c565b610ea2565b61053a6105f23660046151bd565b610f18565b61058361060536600461557c565b60009081526022602052604090206001015490565b61053a61062836600461567c565b610f52565b610583600080516020615faa83398151915281565b61053a610650366004615595565b61106d565b600d5461055690600160c01b90046001600160401b031681565b61053a61067d366004615595565b611093565b61053a6106903660046156f0565b6110de565b61053a6106a3366004615485565b61115a565b6105566106b636600461557c565b611361565b61058360155481565b61053a6106d236600461557c565b611371565b61053a61150d565b60185461050f906001600160a01b031681565b61053a6107003660046151bd565b611531565b6104b96107133660046152ab565b61154c565b61053a61072636600461514a565b61155f565b61053a61073936600461567c565b61159b565b61053a61074c366004615184565b6115fd565b61055661075f36600461557c565b6118f3565b61058361077236600461557c565b611903565b61053a61078536600461570b565b61192e565b61053a6107983660046155f4565b611afa565b60865460ff166104b9565b61050f6107b636600461557c565b611b56565b6104ef611b61565b61053a6107d13660046156c2565b611bef565b6105836107e436600461514a565b611e2a565b61053a6107f736600461514a565b611e82565b61058360145481565b61053a6108133660046153ee565b611ece565b610583600f5481565b60035461050f906001600160a01b031681565b61053a6108423660046154e8565b612018565b61058361085536600461557c565b601b6020526000908152604090205481565b61053a612269565b61053a61087d36600461514a565b61228a565b61058360105481565b600d5461055690600160801b90046001600160401b031681565b600e5461055690600160401b90046001600160401b031681565b6104b96108cd366004615595565b60009182526022602090815260408084206001600160a01b0393909316845291905290205460ff1690565b610583633b9aca0081565b610583600081565b61053a61091936600461527d565b6122fe565b61058361092c3660046152d7565b6123b3565b600d5461055690600160401b90046001600160401b031681565b61053a61095936600461531b565b61264a565b61053a61096c3660046156f0565b612721565b61053a61097f3660046151fe565b6127d5565b61058360015481565b61053a61099b3660046153ee565b612811565b600e54610556906001600160401b031681565b6105566109c136600461557c565b612e7f565b61053a6109d436600461570b565b612e8f565b6104ef6109e736600461557c565b612eea565b61058360165481565b610556610a0336600461557c565b613066565b61053a610a16366004615595565b613076565b600d54610556906001600160401b031681565b610556610a3c36600461557c565b61309c565b60065461050f906001600160a01b031681565b61058360175481565b610583670de0b6b3a764000081565b610a7f610a7a36600461567c565b6130ac565b604080519283526020830191909152016104c5565b61053a610aa2366004615595565b613102565b61053a610ab5366004615655565b6131b3565b6104b9610ac8366004615184565b6001600160a01b0391821660009081526020808052604080832093909416825291909152205460ff1690565b61058360135481565b610583610b0b36600461557c565b601c6020526000908152604090205481565b61053a610b2b36600461570b565b61335b565b60055461050f906001600160a01b031681565b610b78610b5136600461557c565b601a6020526000908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016104c5565b60006001600160e01b03198216636e44396d60e01b1480610bc957506001600160e01b03198216632303fc0360e01b145b80610be457506001600160e01b0319821663f7c618c160e01b145b80610bff57506001600160e01b0319821663aa283ab960e01b145b80610c1a57506001600160e01b03198216637965db0b60e01b145b80610c3557506001600160e01b03198216635b5e139f60e01b145b80610c5057506001600160e01b031982166380ac58cd60e01b145b80610c6b57506001600160e01b031982166301ffc9a760e01b145b92915050565b6000818152601d60205260408120546001600160a01b0316610cbe5760405162461bcd60e51b81526020600482015260016024820152601960f91b60448201526064015b60405180910390fd5b6000828152601f60205260409020546001600160a01b0316610c6b565b6000610ce682613482565b9050806001600160a01b0316836001600160a01b03161415610d2f5760405162461bcd60e51b8152602060048201526002602482015261333560f01b6044820152606401610cb5565b336001600160a01b0382161480610d6757506001600160a01b03811660009081526020808052604080832033845290915290205460ff165b610d835760405162461bcd60e51b8152600401610cb590615be3565b610d8d83836134d0565b505050565b6018546001600160a01b03163314610dbc5760405162461bcd60e51b8152600401610cb590615bc8565b6005546001600160a01b0384811691161415610dff5760405162461bcd60e51b8152602060048201526002602482015261032360f41b6044820152606401610cb5565b610e136001600160a01b038416838361353e565b816001600160a01b0316836001600160a01b03167ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b64883604051610e5891815260200190565b60405180910390a3505050565b600a8181548110610e7557600080fd5b9060005260206000209060049182820401919006600802915054906101000a90046001600160401b031681565b60865460ff1615610ec55760405162461bcd60e51b8152600401610cb590615b50565b3381610ed182826135a1565b610eed5760405162461bcd60e51b8152600401610cb590615be3565b6000838152601a602052604090208054600390910154610d8d918591610f139190615db5565b61361e565b3381610f2482826135a1565b610f405760405162461bcd60e51b8152600401610cb590615be3565b610f4b8585856136af565b5050505050565b60865460ff1615610f755760405162461bcd60e51b8152600401610cb590615b50565b6000828152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290610fbc6137e6565b5090506000610fcc85848461386b565b91505080610f4b57600654600854610ff3916001600160a01b0391821691339116876138b2565b6000858152601a602052604081206002018054869290611014908490615c52565b925050819055507f10c4de39a7e804616cdc1b2dbf59fe6db0ed0d54ff69cef9c8fc024f79c7d47e8585856040015161104d9190615c52565b604080519283526020830191909152015b60405180910390a15050505050565b60008281526022602052604090206001015461108981336138f0565b610d8d8383613970565b6001600160a01b03811633146110d05760405162461bcd60e51b8152602060048201526002602482015261373160f01b6044820152606401610cb5565b6110da82826139f5565b5050565b600080516020615faa8339815191526110f781336138f0565b600e805467ffffffffffffffff60801b1916600160801b6001600160401b038516908102919091179091556040519081527f0cedd128b637e635da421319ae981d7968b7a477c1fa3b10275fac22ecbd51a6906020015b60405180910390a15050565b600080516020615faa83398151915261117381336138f0565b828280518251148015611187575060008251115b6111b75760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610cb5565b60005b600182516111c89190615e03565b811161130557633b9aca006001600160401b03168282815181106111ee576111ee615f15565b60200260200101516001600160401b03161115801561123c5750633b9aca006001600160401b031683828151811061122857611228615f15565b60200260200101516001600160401b031611155b61126c5760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610cb5565b80156112f3578261127e600183615e03565b8151811061128e5761128e615f15565b60200260200101516001600160401b03168382815181106112b1576112b1615f15565b60200260200101516001600160401b0316116112f35760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610cb5565b806112fd81615eba565b9150506111ba565b508451611319906011906020880190614f17565b50835161132d906012906020870190614f17565b507f275781d4ec4992e53f64326606b9f7eb81a89baf476df8de6d0410fd218e7be36011601260405161105e929190615b18565b60118181548110610e7557600080fd5b6018546001600160a01b0316331461139b5760405162461bcd60e51b8152600401610cb590615bc8565b6113a3613a78565b60175560135442106113c4576015546113bc9082615c95565b601455611406565b6000426013546113d49190615e03565b90506000601454826113e69190615db5565b6015549091506113f68285615c52565b6114009190615c95565b60145550505b6005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561144a57600080fd5b505afa15801561145e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611482919061563c565b9050601554816114929190615c95565b60145411156114c85760405162461bcd60e51b8152602060048201526002602482015261191960f11b6044820152606401610cb5565b4260168190556015546114da91615c52565b6013556040518281527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d9060200161114e565b600080516020615faa83398151915261152681336138f0565b61152e613ae0565b50565b610d8d838383604051806020016040528060008152506127d5565b600061155883836135a1565b9392505050565b600080516020615f8a83398151915261157881336138f0565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020615faa8339815191526115b481336138f0565b600f839055601082905560408051848152602081018490527fa0aa01eac9422dea36b84eb0bbc758e72643fbdbc72a4fd205d51c738803598291015b60405180910390a1505050565b602154610100900460ff1680611616575060215460ff16155b6116325760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015611654576021805461ffff19166101011790555b816001600160a01b03811661168f5760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610cb5565b611697613b73565b61169f613bee565b600680546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b1580156116f357600080fd5b505afa158015611707573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172b9190615167565b600860006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b15801561178a57600080fd5b505afa15801561179e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c29190615167565b600780546001600160a01b03199081166001600160a01b0393841617909155600580549091168583161790556008546040805163313ce56760e01b81529051919092169163313ce567916004808301926020929190829003018186803b15801561182b57600080fd5b505afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611863919061573e565b61186e90600a615d0a565b60005560065461189690600080516020615f8a833981519152906001600160a01b0316613c4d565b6118bc600080516020615faa833981519152600080516020615f8a833981519152613c57565b6118d4600080516020615f8a83398151915280613c57565b6118dc613cab565b508015610d8d576021805461ff0019169055505050565b600b8181548110610e7557600080fd5b6000818152601a602052604081208054600390910154610c6b9184916119299190615db5565b613d03565b600080516020615faa83398151915261194781336138f0565b82633b9aca00816001600160401b031611156119895760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610cb5565b82633b9aca00816001600160401b031611156119cb5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610cb5565b836001600160401b0316856001600160401b03161115611a115760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610cb5565b600d80546fffffffffffffffffffffffffffffffff16600160c01b6001600160401b038781169190910267ffffffffffffffff60801b191691909117600160801b91881691820217909155600754604051635b749f3560e01b815260048101929092526001600160a01b031690635b749f3590602401600060405180830381600087803b158015611aa157600080fd5b505af1158015611ab5573d6000803e3d6000fd5b5050604080516001600160401b03808a168252881660208201527f686faddec2d8b23f0f43c10006482b63941b927c9a98339cd78514b67139ad67935001905061105e565b600080516020615faa833981519152611b1381336138f0565b8151611b26906019906020850190614fcf565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad8260405161114e9190615b3d565b6000610c6b82613482565b60198054611b6e90615e85565b80601f0160208091040260200160405190810160405280929190818152602001828054611b9a90615e85565b8015611be75780601f10611bbc57610100808354040283529160200191611be7565b820191906000526020600020905b815481529060010190602001808311611bca57829003601f168201915b505050505081565b60865460ff1615611c125760405162461bcd60e51b8152600401610cb590615b50565b3383611c1e82826135a1565b611c3a5760405162461bcd60e51b8152600401610cb590615be3565b6000858152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290611c816137e6565b509050600080611c9289858561386b565b915091508060001415611e1f57600e5460208501514291611cc491600160801b9091046001600160401b031690615c52565b11158015611cd157508188105b8015611ce05750836040015188105b8015611d255750600d54600160401b90046001600160401b0316611d048984615e03565b611d0e9190615db5565b633b9aca008560600151611d229190615db5565b11155b8015611d725750600d546040850151600160401b9091046001600160401b031690611d51908a90615e03565b611d5b9190615db5565b633b9aca008560600151611d6f9190615db5565b11155b611da35760405162461bcd60e51b8152602060048201526002602482015261333360f01b6044820152606401610cb5565b6000898152601a6020526040812060020180548a9290611dc4908490615e03565b925050819055507f10c4de39a7e804616cdc1b2dbf59fe6db0ed0d54ff69cef9c8fc024f79c7d47e89898660400151611dfd9190615e03565b6040805192835260208301919091520160405180910390a1611e1f8789613d67565b505050505050505050565b60006001600160a01b038216611e665760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610cb5565b506001600160a01b03166000908152601e602052604090205490565b6007546001600160a01b03163314611eac5760405162461bcd60e51b8152600401610cb590615bc8565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60865460ff1615611ef15760405162461bcd60e51b8152600401610cb590615b50565b6000611efb6137e6565b5090506000805b8351811015611fd4576000848281518110611f1f57611f1f615f15565b60200260200101519050611f4a816000908152601d60205260409020546001600160a01b0316151590565b15611fc1576000818152601a602090815260408083208151608081018352815481526001820154938101939093526002810154918301919091526003015460608201529080611f9a84848961386b565b915091508060011415611fbd57611fb082613eb7565b611fba9087615c52565b95505b5050505b5080611fcc81615eba565b915050611f02565b5060408051338152602081018390527f4a9b62c74532d4448574775253ac495abc6f658b1284e9f28508a23135eeb641910160405180910390a1610d8d3382613d67565b600080516020615faa83398151915261203181336138f0565b838380518251148015612045575060008251115b6120755760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610cb5565b60005b600182516120869190615e03565b81116121c357633b9aca006001600160401b03168282815181106120ac576120ac615f15565b60200260200101516001600160401b0316111580156120fa5750633b9aca006001600160401b03168382815181106120e6576120e6615f15565b60200260200101516001600160401b031611155b61212a5760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610cb5565b80156121b1578261213c600183615e03565b8151811061214c5761214c615f15565b60200260200101516001600160401b031683828151811061216f5761216f615f15565b60200260200101516001600160401b0316116121b15760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610cb5565b806121bb81615eba565b915050612078565b508360ff16600114156121fd5785516121e3906009906020890190614f17565b5084516121f790600a906020880190614f17565b50612226565b855161221090600b906020890190614f17565b50845161222490600c906020880190614f17565b505b7f03c94e5b4f32a4b9a2709b098207aebe4cc92c950987ee077776cc2300adcde286868660405161225993929190615adf565b60405180910390a1505050505050565b600080516020615faa83398151915261228281336138f0565b61152e613cab565b6018546001600160a01b031633146122b45760405162461bcd60e51b8152600401610cb590615bc8565b601880546001600160a01b0319166001600160a01b0383169081179091556040517f1c794a043683a294127c95bc365bae91b63b651eb9884a2c9120afee2bb690b490600090a250565b6001600160a01b03821633141561233c5760405162461bcd60e51b8152602060048201526002602482015261199b60f11b6044820152606401610cb5565b336000818152602080805260408083206001600160a01b0387168085529252909120805460ff1916841515179055906001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516123a7911515815260200190565b60405180910390a35050565b60006123c160865460ff1690565b156123de5760405162461bcd60e51b8152600401610cb590615b50565b856001600160a01b0381166124195760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610cb5565b6000851161244e5760405162461bcd60e51b8152602060048201526002602482015261323760f01b6044820152606401610cb5565b60065460085461246d916001600160a01b0391821691339116896138b2565b60006124776137e6565b915050848111156124af5760405162461bcd60e51b8152602060048201526002602482015261064760f31b6044820152606401610cb5565b600080546124bd8389615db5565b6124c79190615c95565b905060006124d689838a613efa565b90508581101561250d5760405162461bcd60e51b8152602060048201526002602482015261323960f01b6044820152606401610cb5565b600d5461252b908290600160401b90046001600160401b0316615db5565b612539633b9aca008a615db5565b111561256c5760405162461bcd60e51b8152602060048201526002602482015261033360f41b6044820152606401610cb5565b61257a600280546001019055565b600254945061258a8560006140b0565b816001600082825461259c9190615c52565b909155505060408051608081018252848152426020808301918252828401858152606084018d815260008b8152601a90935294909120925183559051600183015551600282015590516003909101556125f58a866140f6565b6040805186815260208101859052908101829052606081018990527f2af29ed8e180e9bfa65515c22e3af766d15e852ec59b9666d6eeaef8a97565929060800160405180910390a15050505095945050505050565b600080516020615f8a83398151915261266381336138f0565b60005b85518110156126b2576126a0600080516020615faa83398151915287838151811061269357612693615f15565b6020026020010151613970565b806126aa81615eba565b915050612666565b506126cb600080516020615faa83398151915285613970565b6007546126f090600080516020615faa833981519152906001600160a01b0316613970565b50600480546001600160a01b039384166001600160a01b031991821617909155600380549290931691161790555050565b600080516020615faa83398151915261273a81336138f0565b81633b9aca00816001600160401b0316111561277c5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610cb5565b600e80546001600160c01b0316600160c01b6001600160401b038681168202929092179283905560405192041681527f264a4c2e5ed86659859b3c52d1b00a899950c0f3a637d68ca438cc0216dd89bf906020016115f0565b33826127e182826135a1565b6127fd5760405162461bcd60e51b8152600401610cb590615be3565b612809868686866141c6565b505050505050565b60865460ff16156128345760405162461bcd60e51b8152600401610cb590615b50565b60008061283f6137e6565b915091506000600760009054906101000a90046001600160a01b03166001600160a01b031663344844db6040518163ffffffff1660e01b815260040160206040518083038186803b15801561289357600080fd5b505afa1580156128a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128cb919061563c565b600d54909150600090633b9aca00906128f490600160801b90046001600160401b031684615db5565b6128fe9190615c95565b600d54909150633b9aca009061292490600160c01b90046001600160401b031684615db5565b61292e9190615c95565b600154116129635760405162461bcd60e51b81526020600482015260026024820152610ccd60f21b6044820152606401610cb5565b600080600087516001600160401b0381111561298157612981615f2b565b6040519080825280602002602001820160405280156129c657816020015b604080518082019091526000808252602082015281526020019060019003908161299f5790505b50905060005b8851811015612b825760008982815181106129e9576129e9615f15565b6020908102919091018101516000818152601d9092526040909120549091506001600160a01b03168015612b6d576000828152601a602090815260408083208151608081018352815481526001820154938101939093526002810154918301919091526003015460608201529080612a6285848f61386b565b915091508060011415612a8957612a7882613eb7565b612a82908a615c52565b9850612b56565b600e5460208401514291612aae91600160801b9091046001600160401b031690615c52565b11612b5657612abd858461420e565b60006001548b1115612aed578a633b9aca00600154612adc9190615db5565b612ae69190615c95565b9050612af4565b50633b9aca005b600080612b0685876060015185614269565b9092509050612b15818c615c52565b9a506040518060400160405280886001600160a01b03168152602001838152508a8a81518110612b4757612b47615f15565b60200260200101819052505050505b8960015411612b69575050505050612b82565b5050505b50508080612b7a90615eba565b9150506129cc565b5060008415612bb757612b96856002615db5565b633b9aca00600154612ba89190615db5565b612bb29190615c95565b612bba565b60005b9050633b9aca00612cd0826011805480602002602001604051908101604052809291908181526020018280548015612c4357602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612c005790505b50505050506012805480602002602001604051908101604052809291908181526020018280548015612cc657602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612c835790505b50505050506143dd565b612ce3906001600160401b031685615db5565b612ced9190615c95565b92506010548310612d0057601054612d02565b825b92506000633b9aca00612d1789612710615db5565b612d219190615db5565b600054600d548990612d4c906001600160401b03600160801b8204811691600160c01b900416615e1a565b612d57906005615dd4565b6001600160401b0316612d6a9190615db5565b612d749190615db5565b612d7e9190615c95565b9050808410612d8d5780612d8f565b835b93507fb789efbabfeba5ae006c34c3b3c17f6b1cf34ab2ac684be93d1e64da000b5be78a8433612dbf8989615c52565b604051612dcf9493929190615a33565b60405180910390a160005b8a51811015612e5f576000848281518110612df757612df7615f15565b6020026020010151602001511115612e4d57612e4d848281518110612e1e57612e1e615f15565b602002602001015160000151858381518110612e3c57612e3c615f15565b602002602001015160200151613d67565b80612e5781615eba565b915050612dda565b50612e7333612e6e8787615c52565b613d67565b50505050505050505050565b60098181548110610e7557600080fd5b6004546001600160a01b03163314612eb95760405162461bcd60e51b8152600401610cb590615bc8565b600e80546001600160401b03928316600160401b026001600160801b03199091169290931691909117919091179055565b6000818152601d60205260409020546060906001600160a01b0316612f355760405162461bcd60e51b81526020600482015260016024820152601960f91b6044820152606401610cb5565b8160005b8115612f5f5780612f4981615eba565b9150612f589050600a83615c95565b9150612f39565b6000816001600160401b03811115612f7957612f79615f2b565b6040519080825280601f01601f191660200182016040528015612fa3576020820181803683370190505b5090505b841561300e57612fb8600183615e03565b9150612fc5600a86615ed5565b612fd0906030615c52565b60f81b818381518110612fe557612fe5615f15565b60200101906001600160f81b031916908160001a905350613007600a86615c95565b9450612fa7565b60006019805461301d90615e85565b905011613039576040518060200160405280600081525061305d565b60198160405160200161304d9291906158ee565b6040516020818303038152906040525b95945050505050565b60128181548110610e7557600080fd5b60008281526022602052604090206001015461309281336138f0565b610d8d83836139f5565b600c8181548110610e7557600080fd5b6000828152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015281906130f68185614726565b92509250509250929050565b600080516020615faa83398151915261311b81336138f0565b816001600160a01b0381166131565760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610cb5565b6015849055601880546001600160a01b0319166001600160a01b0385169081179091556040518581527fe139be2fc520b685c93d718b643b5d8c42fc57b5724201180c5d765635467312906020015b60405180910390a250505050565b60865460ff16156131d65760405162461bcd60e51b8152600401610cb590615b50565b33836131e282826135a1565b6131fe5760405162461bcd60e51b8152600401610cb590615be3565b6000858152601a60209081526040808320815160808101835281548152600182015493810193909352600281015491830191909152600301546060820152906132456137e6565b50905060008061325689858561386b565b915091508060001415611e1f57600e546020850151429161328891600160801b9091046001600160401b031690615c52565b11156132bb5760405162461bcd60e51b8152602060048201526002602482015261333160f01b6044820152606401610cb5565b6132c5898561420e565b60006132e08386606001516132db6001546147ce565b614269565b509050878110156133185760405162461bcd60e51b8152602060048201526002602482015261199960f11b6044820152606401610cb5565b604080518b8152602081018390527f2f06d076c30d294b959d7aa34f40d448e45f487492a47889f02831bb06fee6bf910160405180910390a1612e738982613d67565b600080516020615faa83398151915261337481336138f0565b81633b9aca00816001600160401b031611156133b65760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610cb5565b6133c08385615dd4565b6001600160401b03166133d86002633b9aca00615d0a565b116134095760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610cb5565b600d80546001600160801b031916600160401b6001600160401b0387811691820267ffffffffffffffff1916929092179186169182179092556040805192835260208301919091527fb556fe5cb4a1a8243b8d5000bbefd6f8b868adcac2765cd4a30ac9320ff1a0b6910160405180910390a150505050565b6000818152601d60205260409020546001600160a01b0316806134cb5760405162461bcd60e51b81526020600482015260016024820152601960f91b6044820152606401610cb5565b919050565b6000818152601f6020526040902080546001600160a01b0319166001600160a01b038416908117909155819061350582613482565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6040516001600160a01b038316602482015260448101829052610d8d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526148c7565b6000806135ad83613482565b9050806001600160a01b0316846001600160a01b031614806135e857506000838152601f60205260409020546001600160a01b038581169116145b8061361657506001600160a01b038082166000908152602080805260408083209388168352929052205460ff165b949350505050565b61362882826140b0565b6000828152601c60205260409020548015610d8d576000838152601c60209081526040808320839055601d9091529020546005546001600160a01b03918216916136749116828461353e565b806001600160a01b03167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486836040516131a591815260200190565b826001600160a01b03166136c282613482565b6001600160a01b0316146136e85760405162461bcd60e51b8152600401610cb590615bc8565b6001600160a01b0382166137235760405162461bcd60e51b8152602060048201526002602482015261191b60f11b6044820152606401610cb5565b61372e6000826134d0565b6001600160a01b0383166000908152601e60205260408120805460019290613757908490615e03565b90915550506001600160a01b0382166000908152601e60205260408120805460019290613785908490615c52565b90915550506000818152601d602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600354604080516341f654f760e01b8152815160009384936001600160a01b03909116926341f654f79260048083019392829003018186803b15801561382b57600080fd5b505afa15801561383f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613863919061569e565b915091509091565b600080600080600061387d8787614726565b9150915081600014806138905750806001145b156138a45761389f888861420e565b600192505b50925090505b935093915050565b6040516001600160a01b03808516602483015283166044820152606481018290526138ea9085906323b872dd60e01b9060840161356a565b50505050565b60008281526022602090815260408083206001600160a01b038516845290915290205460ff166110da5761392e816001600160a01b03166014614999565b613939836020614999565b60405160200161394a92919061598c565b60408051601f198184030181529082905262461bcd60e51b8252610cb591600401615b3d565b60008281526022602090815260408083206001600160a01b038516845290915290205460ff166110da5760008281526022602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008281526022602090815260408083206001600160a01b038516845290915290205460ff16156110da5760008281526022602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600060015460001415613a8c575060175490565b600154670de0b6b3a7640000601454601654613aa6614b34565b613ab09190615e03565b613aba9190615db5565b613ac49190615db5565b613ace9190615c95565b601754613adb9190615c52565b905090565b60865460ff16613b295760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610cb5565b6086805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b602154610100900460ff1680613b8c575060215460ff16155b613ba85760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015613bca576021805461ffff19166101011790555b613bd2614b4f565b613bda614bb9565b801561152e576021805461ff001916905550565b602154610100900460ff1680613c07575060215460ff16155b613c235760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015613c45576021805461ffff19166101011790555b613bda614b4f565b6110da8282613970565b600082815260226020526040902060010154819060405184907fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff90600090a460009182526022602052604090912060010155565b60865460ff1615613cce5760405162461bcd60e51b8152600401610cb590615b50565b6086805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613b563390565b6000828152601c60209081526040808320548354601b90935290832054909190670de0b6b3a764000090613d35613a78565b613d3f9190615e03565b613d499086615db5565b613d539190615c95565b613d5d9190615c95565b6115589190615c52565b60065460408051629032ff60e51b815290516000926001600160a01b0316916312065fe0916004808301926020929190829003018186803b158015613dab57600080fd5b505afa158015613dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de3919061563c565b9050818110158015613df55750600082115b15613e1857600654600854610d8d916001600160a01b03918216911685856138b2565b8115610d8d576000613e2a8284615e03565b600654600854919250613e4b916001600160a01b03908116911686856138b2565b600754604051631a115ff160e01b8152600481018390526001600160a01b03868116602483015290911690631a115ff190604401600060405180830381600087803b158015613e9957600080fd5b505af1158015613ead573d6000803e3d6000fd5b5050505050505050565b600e54600090633b9aca0090613edd90600160c01b90046001600160401b031684615db5565b613ee79190615c95565b9050600f5481106134cb57600f54610c6b565b600080613f1384600154613f0e9190615c52565b6147ce565b9050633b9aca006001600160401b03821610613f565760405162461bcd60e51b8152602060048201526002602482015261323560f01b6044820152606401610cb5565b6000633b9aca00614042836009805480602002602001604051908101604052809291908181526020018280548015613fdf57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411613f9c5790505b5050505050600a805480602002602001604051908101604052809291908181526020018280548015612cc657600091825260209182902080546001600160401b03168452908202830192909160089101808411612c8357905050505050506143dd565b600e5461405891906001600160401b0316615dd4565b6001600160401b031661406b9190615c95565b9050633b9aca0061407c8282615e03565b6140869086615db5565b6140909190615c95565b61409a9085615e03565b90506140a68187615e03565b9695505050505050565b6140b8613a78565b6017556140c3614b34565b6016556140d08282613d03565b6000928352601c6020908152604080852092909255601754601b90915292209190915550565b6001600160a01b0382166000908152601e6020526040812080546001929061411f908490615c52565b90915550506000818152601d602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46141956000838360405180602001604052806000815250614c2e565b6110da5760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610cb5565b6141d18484846136af565b6141dd84848484614c2e565b6138ea5760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610cb5565b8051606082015160009161422191615db5565b905061422d838261361e565b6000838152601b60205260408120819055546142499082615c95565b6001600082825461425a9190615e03565b90915550610d8d905083614d50565b600080633b9aca0061435684600b8054806020026020016040519081016040528092919081815260200182805480156142f357602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116142b05790505b5050505050600c805480602002602001604051908101604052809291908181526020018280548015612cc657600091825260209182902080546001600160401b03168452908202830192909160089101808411612c8357905050505050506143dd565b600e546143739190600160401b90046001600160401b0316615dd4565b6001600160401b03166143869190615c95565b9050633b9aca006143978282615e03565b6143a19086615db5565b6143ab9190615c95565b6143b59085615e03565b90508481106143c9575060009050836138aa565b6143d38186615e03565b9150935093915050565b600082600184516143ee9190615e03565b815181106143fe576143fe615f15565b60200260200101516001600160401b0316846001600160401b03161061444c57816001845161442d9190615e03565b8151811061443d5761443d615f15565b60200260200101519050611558565b8260008151811061445f5761445f615f15565b60200260200101516001600160401b0316846001600160401b031611614492578160008151811061443d5761443d615f15565b600080600185516144a39190615e03565b905060005b60016144b48484615e03565b111561451e5760026144c68484615e03565b6144d09190615c95565b6144da9084615c52565b9050866001600160401b03168682815181106144f8576144f8615f15565b60200260200101516001600160401b031611614516578092506144a8565b8091506144a8565b84838151811061453057614530615f15565b60200260200101516001600160401b031685838151811061455357614553615f15565b60200260200101516001600160401b0316111561464d5785838151811061457c5761457c615f15565b602002602001015186838151811061459657614596615f15565b60200260200101516145a89190615e1a565b8684815181106145ba576145ba615f15565b6020026020010151886145cd9190615e1a565b8685815181106145df576145df615f15565b60200260200101518785815181106145f9576145f9615f15565b602002602001015161460b9190615e1a565b6146159190615dd4565b61461f9190615ca9565b85848151811061463157614631615f15565b60200260200101516146439190615c6a565b9350505050611558565b85838151811061465f5761465f615f15565b602002602001015186838151811061467957614679615f15565b602002602001015161468b9190615e1a565b86848151811061469d5761469d615f15565b6020026020010151886146b09190615e1a565b8684815181106146c2576146c2615f15565b60200260200101518786815181106146dc576146dc615f15565b60200260200101516146ee9190615e1a565b6146f89190615dd4565b6147029190615ca9565b85848151811061471457614714615f15565b60200260200101516146439190615e1a565b600080600083856000015186606001516147409190615db5565b61474a9190615c95565b9050846040015185606001516147609190615c52565b811061476f57600092506147c6565b80856040015186606001516147849190615c52565b61478e9190615e03565b600d5460608701519194506147ae916001600160401b0390911690615db5565b6147bc633b9aca0085615db5565b116147c657600191505b509250929050565b600080633b9aca00600d60109054906101000a90046001600160401b03166001600160401b0316600760009054906101000a90046001600160a01b03166001600160a01b031663344844db6040518163ffffffff1660e01b815260040160206040518083038186803b15801561484357600080fd5b505afa158015614857573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061487b919061563c565b6148859190615db5565b61488f9190615c95565b9050808310156148b957806148a8633b9aca0085615db5565b6148b29190615c95565b91506148c1565b633b9aca0091505b50919050565b600061491c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e0c9092919063ffffffff16565b805190915015610d8d578080602001905181019061493a919061555f565b610d8d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610cb5565b606060006149a8836002615db5565b6149b3906002615c52565b6001600160401b038111156149ca576149ca615f2b565b6040519080825280601f01601f1916602001820160405280156149f4576020820181803683370190505b509050600360fc1b81600081518110614a0f57614a0f615f15565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614a3e57614a3e615f15565b60200101906001600160f81b031916908160001a9053506000614a62846002615db5565b614a6d906001615c52565b90505b6001811115614ae5576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614aa157614aa1615f15565b1a60f81b828281518110614ab757614ab7615f15565b60200101906001600160f81b031916908160001a90535060049490941c93614ade81615e6e565b9050614a70565b5083156115585760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610cb5565b6000806013544210614b4857601354610c6b565b4292915050565b602154610100900460ff1680614b68575060215460ff16155b614b845760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015613bda576021805461ffff1916610101179055801561152e576021805461ff001916905550565b602154610100900460ff1680614bd2575060215460ff16155b614bee5760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015614c10576021805461ffff19166101011790555b6086805460ff19169055801561152e576021805461ff001916905550565b60006001600160a01b0384163b15614d4557604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614c72903390899088908890600401615a01565b602060405180830381600087803b158015614c8c57600080fd5b505af1925050508015614cbc575060408051601f3d908101601f19168201909252614cb9918101906155d7565b60015b614d2b573d808015614cea576040519150601f19603f3d011682016040523d82523d6000602084013e614cef565b606091505b508051614d235760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610cb5565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050613616565b506001949350505050565b6000614d5b82613482565b9050614d686000836134d0565b6001600160a01b0381166000908152601e60205260408120805460019290614d91908490615e03565b90915550506000828152601d6020908152604080832080546001600160a01b0319169055601a9091528082208281556001810183905560028101839055600301829055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6060613616848460008585843b614e655760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cb5565b600080866001600160a01b03168587604051614e8191906158d2565b60006040518083038185875af1925050503d8060008114614ebe576040519150601f19603f3d011682016040523d82523d6000602084013e614ec3565b606091505b5091509150614ed3828286614ede565b979650505050505050565b60608315614eed575081611558565b825115614efd5782518084602001fd5b8160405162461bcd60e51b8152600401610cb59190615b3d565b82805482825590600052602060002090600301600490048101928215614fbf5791602002820160005b83821115614f8a57835183826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302614f40565b8015614fbd5782816101000a8154906001600160401b030219169055600801602081600701049283019260010302614f8a565b505b50614fcb929150615043565b5090565b828054614fdb90615e85565b90600052602060002090601f016020900481019282614ffd5760008555614fbf565b82601f1061501657805160ff1916838001178555614fbf565b82800160010185558215614fbf579182015b82811115614fbf578251825591602001919060010190615028565b5b80821115614fcb5760008155600101615044565b60006001600160401b0383111561507157615071615f2b565b615084601f8401601f1916602001615bff565b905082815283838301111561509857600080fd5b828260208301376000602084830101529392505050565b80356134cb81615f41565b600082601f8301126150cb57600080fd5b813560206150e06150db83615c2f565b615bff565b80838252828201915082860187848660051b890101111561510057600080fd5b60005b858110156151265761511482615133565b84529284019290840190600101615103565b5090979650505050505050565b80356001600160401b03811681146134cb57600080fd5b60006020828403121561515c57600080fd5b813561155881615f41565b60006020828403121561517957600080fd5b815161155881615f41565b6000806040838503121561519757600080fd5b82356151a281615f41565b915060208301356151b281615f41565b809150509250929050565b6000806000606084860312156151d257600080fd5b83356151dd81615f41565b925060208401356151ed81615f41565b929592945050506040919091013590565b6000806000806080858703121561521457600080fd5b843561521f81615f41565b9350602085013561522f81615f41565b92506040850135915060608501356001600160401b0381111561525157600080fd5b8501601f8101871361526257600080fd5b61527187823560208401615058565b91505092959194509250565b6000806040838503121561529057600080fd5b823561529b81615f41565b915060208301356151b281615f56565b600080604083850312156152be57600080fd5b82356152c981615f41565b946020939093013593505050565b600080600080600060a086880312156152ef57600080fd5b85356152fa81615f41565b97602087013597506040870135966060810135965060800135945092505050565b6000806000806080858703121561533157600080fd5b84356001600160401b0381111561534757600080fd5b8501601f8101871361535857600080fd5b803560206153686150db83615c2f565b8083825282820191508285018b848660051b880101111561538857600080fd5b600095505b848610156153b45780356153a081615f41565b83526001959095019491830191830161538d565b5097506153c490508882016150af565b95505050506153d5604086016150af565b91506153e3606086016150af565b905092959194509250565b6000602080838503121561540157600080fd5b82356001600160401b0381111561541757600080fd5b8301601f8101851361542857600080fd5b80356154366150db82615c2f565b80828252848201915084840188868560051b870101111561545657600080fd5b600094505b8385101561547957803583526001949094019391850191850161545b565b50979650505050505050565b6000806040838503121561549857600080fd5b82356001600160401b03808211156154af57600080fd5b6154bb868387016150ba565b935060208501359150808211156154d157600080fd5b506154de858286016150ba565b9150509250929050565b6000806000606084860312156154fd57600080fd5b83356001600160401b038082111561551457600080fd5b615520878388016150ba565b9450602086013591508082111561553657600080fd5b50615543868287016150ba565b925050604084013561555481615f7a565b809150509250925092565b60006020828403121561557157600080fd5b815161155881615f56565b60006020828403121561558e57600080fd5b5035919050565b600080604083850312156155a857600080fd5b8235915060208301356151b281615f41565b6000602082840312156155cc57600080fd5b813561155881615f64565b6000602082840312156155e957600080fd5b815161155881615f64565b60006020828403121561560657600080fd5b81356001600160401b0381111561561c57600080fd5b8201601f8101841361562d57600080fd5b61361684823560208401615058565b60006020828403121561564e57600080fd5b5051919050565b60008060006060848603121561566a57600080fd5b8335925060208401356151ed81615f41565b6000806040838503121561568f57600080fd5b50508035926020909101359150565b600080604083850312156156b157600080fd5b505080516020909101519092909150565b6000806000606084860312156156d757600080fd5b8335925060208401359150604084013561555481615f41565b60006020828403121561570257600080fd5b61155882615133565b6000806040838503121561571e57600080fd5b61572783615133565b915061573560208401615133565b90509250929050565b60006020828403121561575057600080fd5b815161155881615f7a565b600081518084526020808501945080840160005b838110156157945781516001600160401b03168752958201959082019060010161576f565b509495945050505050565b805480835260008281526020808220940193909190825b826003820110156158055781546001600160401b038082168852604082811c821660208a0152608083811c9092169089015260c09190911c6060880152909501946001909101906004016157b6565b90549082811015615826576001600160401b03821686526020909501946001015b82811015615848576001600160401b03604083901c1686526020909501946001015b8281101561586a576001600160401b03608083901c1686526020909501946001015b828110156158805760c082901c86526020860195505b5093949350505050565b600081518084526158a2816020860160208601615e42565b601f01601f19169290920160200192915050565b600081516158c8818560208601615e42565b9290920192915050565b600082516158e4818460208701615e42565b9190910192915050565b600080845481600182811c91508083168061590a57607f831692505b602080841082141561592a57634e487b7160e01b86526022600452602486fd5b81801561593e576001811461594f5761597c565b60ff1986168952848901965061597c565b60008b81526020902060005b868110156159745781548b82015290850190830161595b565b505084890196505b50505050505061305d81856158b6565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516159c4816017850160208801615e42565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516159f5816028840160208801615e42565b01602801949350505050565b60006001600160a01b038087168352808616602084015250836040830152608060608301526140a6608083018461588a565b6080808252855190820181905260009060209060a0840190828901845b82811015615a6c57815184529284019290840190600101615a50565b5050508381038285015286518082528783019183019060005b81811015615ab557835180516001600160a01b031684528501518584015292840192604090920191600101615a85565b50506001600160a01b03871660408601529250615ad0915050565b82606083015295945050505050565b606081526000615af2606083018661575b565b8281036020840152615b04818661575b565b91505060ff83166040830152949350505050565b604081526000615b2b604083018561579f565b828103602084015261305d818561579f565b602081526000611558602083018461588a565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600190820152603160f81b604082015260600190565b602080825260029082015261323160f01b604082015260600190565b604051601f8201601f191681016001600160401b0381118282101715615c2757615c27615f2b565b604052919050565b60006001600160401b03821115615c4857615c48615f2b565b5060051b60200190565b60008219821115615c6557615c65615ee9565b500190565b60006001600160401b03808316818516808303821115615c8c57615c8c615ee9565b01949350505050565b600082615ca457615ca4615eff565b500490565b60006001600160401b0380841680615cc357615cc3615eff565b92169190910492915050565b600181815b808511156147c6578160001904821115615cf057615cf0615ee9565b80851615615cfd57918102915b93841c9390800290615cd4565b600061155860ff841683600082615d2357506001610c6b565b81615d3057506000610c6b565b8160018114615d465760028114615d5057615d6c565b6001915050610c6b565b60ff841115615d6157615d61615ee9565b50506001821b610c6b565b5060208310610133831016604e8410600b8410161715615d8f575081810a610c6b565b615d998383615ccf565b8060001904821115615dad57615dad615ee9565b029392505050565b6000816000190483118215151615615dcf57615dcf615ee9565b500290565b60006001600160401b0380831681851681830481118215151615615dfa57615dfa615ee9565b02949350505050565b600082821015615e1557615e15615ee9565b500390565b60006001600160401b0383811690831681811015615e3a57615e3a615ee9565b039392505050565b60005b83811015615e5d578181015183820152602001615e45565b838111156138ea5750506000910152565b600081615e7d57615e7d615ee9565b506000190190565b600181811c90821680615e9957607f821691505b602082108114156148c157634e487b7160e01b600052602260045260246000fd5b6000600019821415615ece57615ece615ee9565b5060010190565b600082615ee457615ee4615eff565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461152e57600080fd5b801515811461152e57600080fd5b6001600160e01b03198116811461152e57600080fd5b60ff8116811461152e57600080fdfe5916f72c85af4ac6f7e34636ecc97619c4b2085da099a5d28f3e58436cfbe56255435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a264697066735822122045840058006f230868797238b1a0691e6a0b163718211cd780d1fcfd01a5532c64736f6c63430008070033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106104a15760003560e01c80637bd06a151161026d578063c0212c7211610151578063df136d65116100ce578063e985e9c511610092578063e985e9c514610aba578063ebe2b12b14610af4578063f301af4214610afd578063f5d011c514610b1d578063f7c618c114610b30578063f902fad714610b4357600080fd5b8063df136d6514610a54578063df1b8bd314610a5d578063e048684214610a6c578063e2b01a5e14610a94578063e5234c7a14610aa757600080fd5b8063d1aace9f11610115578063d1aace9f146109f5578063d547741f14610a08578063d5eb058114610a1b578063d7f6328e14610a2e578063dc4c90d314610a4157600080fd5b8063c0212c72146109a0578063c1618dda146109b3578063c628a6f7146109c6578063c87b56dd146109d9578063c8f33c91146109ec57600080fd5b806395d89b41116101ea578063ae3302c2116101ae578063ae3302c214610931578063b126e7e51461094b578063b3b1cb271461095e578063b88d4fde14610971578063b8f3689514610984578063bcb01a801461098d57600080fd5b806395d89b41146104ce5780639f48118f146108f8578063a217fddf14610903578063a22cb4651461090b578063a62b2a3d1461091e57600080fd5b8063873291bb11610231578063873291bb1461086f5780638c6dfaf7146108825780638d5e19f11461088b5780638e240144146108a557806391d14854146108bf57600080fd5b80637bd06a15146108185780637dc0d1d0146108215780638211477a14610834578063840a7698146108475780638456cb591461086757600080fd5b8063386a9525116103945780634d6ed8c4116103115780636c0360eb116102d55780636c0360eb146107bb5780636d59dae7146107c357806370a08231146107d65780637adbf973146107e95780637b0a47ee146107fc5780637b39ecf71461080557600080fd5b80634d6ed8c414610764578063515dc4801461077757806355f804b31461078a5780635c975abb1461079d5780636352211e146107a857600080fd5b8063430c208111610358578063430c208114610705578063472d35b91461071857806347c12e011461072b578063485cc9551461073e57806349a5d3ef1461075157600080fd5b8063386a9525146106bb5780633c6b16ab146106c45780633f4ba83a146106d75780633fc6df6e146106df57806342842e0e146106f257600080fd5b806323b872dd11610422578063324f3815116103e6578063324f38151461065557806336568abe1461066f5780633675441514610682578063367f21b41461069557806338050129146106a857600080fd5b806323b872dd146105e4578063248a9ca3146105f757806324d83b791461061a57806324ea54f41461062d5780632f2ff15d1461064257600080fd5b80630c016dc0116104695780630c016dc01461056e5780630d668087146105915780631171bda9146105ab578063142c3ba0146105be5780631c4b774b146105d157600080fd5b806301ffc9a7146104a657806306fdde03146104ce578063081812fc146104fc578063095ea7b3146105275780630bfab8a71461053c575b600080fd5b6104b96104b43660046155ba565b610b98565b60405190151581526020015b60405180910390f35b6040805180820190915260098152680416e676c65506572760bc1b60208201525b6040516104c59190615b3d565b61050f61050a36600461557c565b610c71565b6040516001600160a01b0390911681526020016104c5565b61053a6105353660046152ab565b610cdb565b005b600e5461055690600160c01b90046001600160401b031681565b6040516001600160401b0390911681526020016104c5565b610583600080516020615f8a83398151915281565b6040519081526020016104c5565b600e5461055690600160801b90046001600160401b031681565b61053a6105b93660046151bd565b610d92565b6105566105cc36600461557c565b610e65565b61053a6105df36600461557c565b610ea2565b61053a6105f23660046151bd565b610f18565b61058361060536600461557c565b60009081526022602052604090206001015490565b61053a61062836600461567c565b610f52565b610583600080516020615faa83398151915281565b61053a610650366004615595565b61106d565b600d5461055690600160c01b90046001600160401b031681565b61053a61067d366004615595565b611093565b61053a6106903660046156f0565b6110de565b61053a6106a3366004615485565b61115a565b6105566106b636600461557c565b611361565b61058360155481565b61053a6106d236600461557c565b611371565b61053a61150d565b60185461050f906001600160a01b031681565b61053a6107003660046151bd565b611531565b6104b96107133660046152ab565b61154c565b61053a61072636600461514a565b61155f565b61053a61073936600461567c565b61159b565b61053a61074c366004615184565b6115fd565b61055661075f36600461557c565b6118f3565b61058361077236600461557c565b611903565b61053a61078536600461570b565b61192e565b61053a6107983660046155f4565b611afa565b60865460ff166104b9565b61050f6107b636600461557c565b611b56565b6104ef611b61565b61053a6107d13660046156c2565b611bef565b6105836107e436600461514a565b611e2a565b61053a6107f736600461514a565b611e82565b61058360145481565b61053a6108133660046153ee565b611ece565b610583600f5481565b60035461050f906001600160a01b031681565b61053a6108423660046154e8565b612018565b61058361085536600461557c565b601b6020526000908152604090205481565b61053a612269565b61053a61087d36600461514a565b61228a565b61058360105481565b600d5461055690600160801b90046001600160401b031681565b600e5461055690600160401b90046001600160401b031681565b6104b96108cd366004615595565b60009182526022602090815260408084206001600160a01b0393909316845291905290205460ff1690565b610583633b9aca0081565b610583600081565b61053a61091936600461527d565b6122fe565b61058361092c3660046152d7565b6123b3565b600d5461055690600160401b90046001600160401b031681565b61053a61095936600461531b565b61264a565b61053a61096c3660046156f0565b612721565b61053a61097f3660046151fe565b6127d5565b61058360015481565b61053a61099b3660046153ee565b612811565b600e54610556906001600160401b031681565b6105566109c136600461557c565b612e7f565b61053a6109d436600461570b565b612e8f565b6104ef6109e736600461557c565b612eea565b61058360165481565b610556610a0336600461557c565b613066565b61053a610a16366004615595565b613076565b600d54610556906001600160401b031681565b610556610a3c36600461557c565b61309c565b60065461050f906001600160a01b031681565b61058360175481565b610583670de0b6b3a764000081565b610a7f610a7a36600461567c565b6130ac565b604080519283526020830191909152016104c5565b61053a610aa2366004615595565b613102565b61053a610ab5366004615655565b6131b3565b6104b9610ac8366004615184565b6001600160a01b0391821660009081526020808052604080832093909416825291909152205460ff1690565b61058360135481565b610583610b0b36600461557c565b601c6020526000908152604090205481565b61053a610b2b36600461570b565b61335b565b60055461050f906001600160a01b031681565b610b78610b5136600461557c565b601a6020526000908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016104c5565b60006001600160e01b03198216636e44396d60e01b1480610bc957506001600160e01b03198216632303fc0360e01b145b80610be457506001600160e01b0319821663f7c618c160e01b145b80610bff57506001600160e01b0319821663aa283ab960e01b145b80610c1a57506001600160e01b03198216637965db0b60e01b145b80610c3557506001600160e01b03198216635b5e139f60e01b145b80610c5057506001600160e01b031982166380ac58cd60e01b145b80610c6b57506001600160e01b031982166301ffc9a760e01b145b92915050565b6000818152601d60205260408120546001600160a01b0316610cbe5760405162461bcd60e51b81526020600482015260016024820152601960f91b60448201526064015b60405180910390fd5b6000828152601f60205260409020546001600160a01b0316610c6b565b6000610ce682613482565b9050806001600160a01b0316836001600160a01b03161415610d2f5760405162461bcd60e51b8152602060048201526002602482015261333560f01b6044820152606401610cb5565b336001600160a01b0382161480610d6757506001600160a01b03811660009081526020808052604080832033845290915290205460ff165b610d835760405162461bcd60e51b8152600401610cb590615be3565b610d8d83836134d0565b505050565b6018546001600160a01b03163314610dbc5760405162461bcd60e51b8152600401610cb590615bc8565b6005546001600160a01b0384811691161415610dff5760405162461bcd60e51b8152602060048201526002602482015261032360f41b6044820152606401610cb5565b610e136001600160a01b038416838361353e565b816001600160a01b0316836001600160a01b03167ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b64883604051610e5891815260200190565b60405180910390a3505050565b600a8181548110610e7557600080fd5b9060005260206000209060049182820401919006600802915054906101000a90046001600160401b031681565b60865460ff1615610ec55760405162461bcd60e51b8152600401610cb590615b50565b3381610ed182826135a1565b610eed5760405162461bcd60e51b8152600401610cb590615be3565b6000838152601a602052604090208054600390910154610d8d918591610f139190615db5565b61361e565b3381610f2482826135a1565b610f405760405162461bcd60e51b8152600401610cb590615be3565b610f4b8585856136af565b5050505050565b60865460ff1615610f755760405162461bcd60e51b8152600401610cb590615b50565b6000828152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290610fbc6137e6565b5090506000610fcc85848461386b565b91505080610f4b57600654600854610ff3916001600160a01b0391821691339116876138b2565b6000858152601a602052604081206002018054869290611014908490615c52565b925050819055507f10c4de39a7e804616cdc1b2dbf59fe6db0ed0d54ff69cef9c8fc024f79c7d47e8585856040015161104d9190615c52565b604080519283526020830191909152015b60405180910390a15050505050565b60008281526022602052604090206001015461108981336138f0565b610d8d8383613970565b6001600160a01b03811633146110d05760405162461bcd60e51b8152602060048201526002602482015261373160f01b6044820152606401610cb5565b6110da82826139f5565b5050565b600080516020615faa8339815191526110f781336138f0565b600e805467ffffffffffffffff60801b1916600160801b6001600160401b038516908102919091179091556040519081527f0cedd128b637e635da421319ae981d7968b7a477c1fa3b10275fac22ecbd51a6906020015b60405180910390a15050565b600080516020615faa83398151915261117381336138f0565b828280518251148015611187575060008251115b6111b75760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610cb5565b60005b600182516111c89190615e03565b811161130557633b9aca006001600160401b03168282815181106111ee576111ee615f15565b60200260200101516001600160401b03161115801561123c5750633b9aca006001600160401b031683828151811061122857611228615f15565b60200260200101516001600160401b031611155b61126c5760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610cb5565b80156112f3578261127e600183615e03565b8151811061128e5761128e615f15565b60200260200101516001600160401b03168382815181106112b1576112b1615f15565b60200260200101516001600160401b0316116112f35760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610cb5565b806112fd81615eba565b9150506111ba565b508451611319906011906020880190614f17565b50835161132d906012906020870190614f17565b507f275781d4ec4992e53f64326606b9f7eb81a89baf476df8de6d0410fd218e7be36011601260405161105e929190615b18565b60118181548110610e7557600080fd5b6018546001600160a01b0316331461139b5760405162461bcd60e51b8152600401610cb590615bc8565b6113a3613a78565b60175560135442106113c4576015546113bc9082615c95565b601455611406565b6000426013546113d49190615e03565b90506000601454826113e69190615db5565b6015549091506113f68285615c52565b6114009190615c95565b60145550505b6005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561144a57600080fd5b505afa15801561145e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611482919061563c565b9050601554816114929190615c95565b60145411156114c85760405162461bcd60e51b8152602060048201526002602482015261191960f11b6044820152606401610cb5565b4260168190556015546114da91615c52565b6013556040518281527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d9060200161114e565b600080516020615faa83398151915261152681336138f0565b61152e613ae0565b50565b610d8d838383604051806020016040528060008152506127d5565b600061155883836135a1565b9392505050565b600080516020615f8a83398151915261157881336138f0565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020615faa8339815191526115b481336138f0565b600f839055601082905560408051848152602081018490527fa0aa01eac9422dea36b84eb0bbc758e72643fbdbc72a4fd205d51c738803598291015b60405180910390a1505050565b602154610100900460ff1680611616575060215460ff16155b6116325760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015611654576021805461ffff19166101011790555b816001600160a01b03811661168f5760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610cb5565b611697613b73565b61169f613bee565b600680546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b1580156116f357600080fd5b505afa158015611707573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172b9190615167565b600860006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b15801561178a57600080fd5b505afa15801561179e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c29190615167565b600780546001600160a01b03199081166001600160a01b0393841617909155600580549091168583161790556008546040805163313ce56760e01b81529051919092169163313ce567916004808301926020929190829003018186803b15801561182b57600080fd5b505afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611863919061573e565b61186e90600a615d0a565b60005560065461189690600080516020615f8a833981519152906001600160a01b0316613c4d565b6118bc600080516020615faa833981519152600080516020615f8a833981519152613c57565b6118d4600080516020615f8a83398151915280613c57565b6118dc613cab565b508015610d8d576021805461ff0019169055505050565b600b8181548110610e7557600080fd5b6000818152601a602052604081208054600390910154610c6b9184916119299190615db5565b613d03565b600080516020615faa83398151915261194781336138f0565b82633b9aca00816001600160401b031611156119895760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610cb5565b82633b9aca00816001600160401b031611156119cb5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610cb5565b836001600160401b0316856001600160401b03161115611a115760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610cb5565b600d80546fffffffffffffffffffffffffffffffff16600160c01b6001600160401b038781169190910267ffffffffffffffff60801b191691909117600160801b91881691820217909155600754604051635b749f3560e01b815260048101929092526001600160a01b031690635b749f3590602401600060405180830381600087803b158015611aa157600080fd5b505af1158015611ab5573d6000803e3d6000fd5b5050604080516001600160401b03808a168252881660208201527f686faddec2d8b23f0f43c10006482b63941b927c9a98339cd78514b67139ad67935001905061105e565b600080516020615faa833981519152611b1381336138f0565b8151611b26906019906020850190614fcf565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad8260405161114e9190615b3d565b6000610c6b82613482565b60198054611b6e90615e85565b80601f0160208091040260200160405190810160405280929190818152602001828054611b9a90615e85565b8015611be75780601f10611bbc57610100808354040283529160200191611be7565b820191906000526020600020905b815481529060010190602001808311611bca57829003601f168201915b505050505081565b60865460ff1615611c125760405162461bcd60e51b8152600401610cb590615b50565b3383611c1e82826135a1565b611c3a5760405162461bcd60e51b8152600401610cb590615be3565b6000858152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290611c816137e6565b509050600080611c9289858561386b565b915091508060001415611e1f57600e5460208501514291611cc491600160801b9091046001600160401b031690615c52565b11158015611cd157508188105b8015611ce05750836040015188105b8015611d255750600d54600160401b90046001600160401b0316611d048984615e03565b611d0e9190615db5565b633b9aca008560600151611d229190615db5565b11155b8015611d725750600d546040850151600160401b9091046001600160401b031690611d51908a90615e03565b611d5b9190615db5565b633b9aca008560600151611d6f9190615db5565b11155b611da35760405162461bcd60e51b8152602060048201526002602482015261333360f01b6044820152606401610cb5565b6000898152601a6020526040812060020180548a9290611dc4908490615e03565b925050819055507f10c4de39a7e804616cdc1b2dbf59fe6db0ed0d54ff69cef9c8fc024f79c7d47e89898660400151611dfd9190615e03565b6040805192835260208301919091520160405180910390a1611e1f8789613d67565b505050505050505050565b60006001600160a01b038216611e665760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610cb5565b506001600160a01b03166000908152601e602052604090205490565b6007546001600160a01b03163314611eac5760405162461bcd60e51b8152600401610cb590615bc8565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60865460ff1615611ef15760405162461bcd60e51b8152600401610cb590615b50565b6000611efb6137e6565b5090506000805b8351811015611fd4576000848281518110611f1f57611f1f615f15565b60200260200101519050611f4a816000908152601d60205260409020546001600160a01b0316151590565b15611fc1576000818152601a602090815260408083208151608081018352815481526001820154938101939093526002810154918301919091526003015460608201529080611f9a84848961386b565b915091508060011415611fbd57611fb082613eb7565b611fba9087615c52565b95505b5050505b5080611fcc81615eba565b915050611f02565b5060408051338152602081018390527f4a9b62c74532d4448574775253ac495abc6f658b1284e9f28508a23135eeb641910160405180910390a1610d8d3382613d67565b600080516020615faa83398151915261203181336138f0565b838380518251148015612045575060008251115b6120755760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610cb5565b60005b600182516120869190615e03565b81116121c357633b9aca006001600160401b03168282815181106120ac576120ac615f15565b60200260200101516001600160401b0316111580156120fa5750633b9aca006001600160401b03168382815181106120e6576120e6615f15565b60200260200101516001600160401b031611155b61212a5760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610cb5565b80156121b1578261213c600183615e03565b8151811061214c5761214c615f15565b60200260200101516001600160401b031683828151811061216f5761216f615f15565b60200260200101516001600160401b0316116121b15760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610cb5565b806121bb81615eba565b915050612078565b508360ff16600114156121fd5785516121e3906009906020890190614f17565b5084516121f790600a906020880190614f17565b50612226565b855161221090600b906020890190614f17565b50845161222490600c906020880190614f17565b505b7f03c94e5b4f32a4b9a2709b098207aebe4cc92c950987ee077776cc2300adcde286868660405161225993929190615adf565b60405180910390a1505050505050565b600080516020615faa83398151915261228281336138f0565b61152e613cab565b6018546001600160a01b031633146122b45760405162461bcd60e51b8152600401610cb590615bc8565b601880546001600160a01b0319166001600160a01b0383169081179091556040517f1c794a043683a294127c95bc365bae91b63b651eb9884a2c9120afee2bb690b490600090a250565b6001600160a01b03821633141561233c5760405162461bcd60e51b8152602060048201526002602482015261199b60f11b6044820152606401610cb5565b336000818152602080805260408083206001600160a01b0387168085529252909120805460ff1916841515179055906001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516123a7911515815260200190565b60405180910390a35050565b60006123c160865460ff1690565b156123de5760405162461bcd60e51b8152600401610cb590615b50565b856001600160a01b0381166124195760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610cb5565b6000851161244e5760405162461bcd60e51b8152602060048201526002602482015261323760f01b6044820152606401610cb5565b60065460085461246d916001600160a01b0391821691339116896138b2565b60006124776137e6565b915050848111156124af5760405162461bcd60e51b8152602060048201526002602482015261064760f31b6044820152606401610cb5565b600080546124bd8389615db5565b6124c79190615c95565b905060006124d689838a613efa565b90508581101561250d5760405162461bcd60e51b8152602060048201526002602482015261323960f01b6044820152606401610cb5565b600d5461252b908290600160401b90046001600160401b0316615db5565b612539633b9aca008a615db5565b111561256c5760405162461bcd60e51b8152602060048201526002602482015261033360f41b6044820152606401610cb5565b61257a600280546001019055565b600254945061258a8560006140b0565b816001600082825461259c9190615c52565b909155505060408051608081018252848152426020808301918252828401858152606084018d815260008b8152601a90935294909120925183559051600183015551600282015590516003909101556125f58a866140f6565b6040805186815260208101859052908101829052606081018990527f2af29ed8e180e9bfa65515c22e3af766d15e852ec59b9666d6eeaef8a97565929060800160405180910390a15050505095945050505050565b600080516020615f8a83398151915261266381336138f0565b60005b85518110156126b2576126a0600080516020615faa83398151915287838151811061269357612693615f15565b6020026020010151613970565b806126aa81615eba565b915050612666565b506126cb600080516020615faa83398151915285613970565b6007546126f090600080516020615faa833981519152906001600160a01b0316613970565b50600480546001600160a01b039384166001600160a01b031991821617909155600380549290931691161790555050565b600080516020615faa83398151915261273a81336138f0565b81633b9aca00816001600160401b0316111561277c5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610cb5565b600e80546001600160c01b0316600160c01b6001600160401b038681168202929092179283905560405192041681527f264a4c2e5ed86659859b3c52d1b00a899950c0f3a637d68ca438cc0216dd89bf906020016115f0565b33826127e182826135a1565b6127fd5760405162461bcd60e51b8152600401610cb590615be3565b612809868686866141c6565b505050505050565b60865460ff16156128345760405162461bcd60e51b8152600401610cb590615b50565b60008061283f6137e6565b915091506000600760009054906101000a90046001600160a01b03166001600160a01b031663344844db6040518163ffffffff1660e01b815260040160206040518083038186803b15801561289357600080fd5b505afa1580156128a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128cb919061563c565b600d54909150600090633b9aca00906128f490600160801b90046001600160401b031684615db5565b6128fe9190615c95565b600d54909150633b9aca009061292490600160c01b90046001600160401b031684615db5565b61292e9190615c95565b600154116129635760405162461bcd60e51b81526020600482015260026024820152610ccd60f21b6044820152606401610cb5565b600080600087516001600160401b0381111561298157612981615f2b565b6040519080825280602002602001820160405280156129c657816020015b604080518082019091526000808252602082015281526020019060019003908161299f5790505b50905060005b8851811015612b825760008982815181106129e9576129e9615f15565b6020908102919091018101516000818152601d9092526040909120549091506001600160a01b03168015612b6d576000828152601a602090815260408083208151608081018352815481526001820154938101939093526002810154918301919091526003015460608201529080612a6285848f61386b565b915091508060011415612a8957612a7882613eb7565b612a82908a615c52565b9850612b56565b600e5460208401514291612aae91600160801b9091046001600160401b031690615c52565b11612b5657612abd858461420e565b60006001548b1115612aed578a633b9aca00600154612adc9190615db5565b612ae69190615c95565b9050612af4565b50633b9aca005b600080612b0685876060015185614269565b9092509050612b15818c615c52565b9a506040518060400160405280886001600160a01b03168152602001838152508a8a81518110612b4757612b47615f15565b60200260200101819052505050505b8960015411612b69575050505050612b82565b5050505b50508080612b7a90615eba565b9150506129cc565b5060008415612bb757612b96856002615db5565b633b9aca00600154612ba89190615db5565b612bb29190615c95565b612bba565b60005b9050633b9aca00612cd0826011805480602002602001604051908101604052809291908181526020018280548015612c4357602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612c005790505b50505050506012805480602002602001604051908101604052809291908181526020018280548015612cc657602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612c835790505b50505050506143dd565b612ce3906001600160401b031685615db5565b612ced9190615c95565b92506010548310612d0057601054612d02565b825b92506000633b9aca00612d1789612710615db5565b612d219190615db5565b600054600d548990612d4c906001600160401b03600160801b8204811691600160c01b900416615e1a565b612d57906005615dd4565b6001600160401b0316612d6a9190615db5565b612d749190615db5565b612d7e9190615c95565b9050808410612d8d5780612d8f565b835b93507fb789efbabfeba5ae006c34c3b3c17f6b1cf34ab2ac684be93d1e64da000b5be78a8433612dbf8989615c52565b604051612dcf9493929190615a33565b60405180910390a160005b8a51811015612e5f576000848281518110612df757612df7615f15565b6020026020010151602001511115612e4d57612e4d848281518110612e1e57612e1e615f15565b602002602001015160000151858381518110612e3c57612e3c615f15565b602002602001015160200151613d67565b80612e5781615eba565b915050612dda565b50612e7333612e6e8787615c52565b613d67565b50505050505050505050565b60098181548110610e7557600080fd5b6004546001600160a01b03163314612eb95760405162461bcd60e51b8152600401610cb590615bc8565b600e80546001600160401b03928316600160401b026001600160801b03199091169290931691909117919091179055565b6000818152601d60205260409020546060906001600160a01b0316612f355760405162461bcd60e51b81526020600482015260016024820152601960f91b6044820152606401610cb5565b8160005b8115612f5f5780612f4981615eba565b9150612f589050600a83615c95565b9150612f39565b6000816001600160401b03811115612f7957612f79615f2b565b6040519080825280601f01601f191660200182016040528015612fa3576020820181803683370190505b5090505b841561300e57612fb8600183615e03565b9150612fc5600a86615ed5565b612fd0906030615c52565b60f81b818381518110612fe557612fe5615f15565b60200101906001600160f81b031916908160001a905350613007600a86615c95565b9450612fa7565b60006019805461301d90615e85565b905011613039576040518060200160405280600081525061305d565b60198160405160200161304d9291906158ee565b6040516020818303038152906040525b95945050505050565b60128181548110610e7557600080fd5b60008281526022602052604090206001015461309281336138f0565b610d8d83836139f5565b600c8181548110610e7557600080fd5b6000828152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015281906130f68185614726565b92509250509250929050565b600080516020615faa83398151915261311b81336138f0565b816001600160a01b0381166131565760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610cb5565b6015849055601880546001600160a01b0319166001600160a01b0385169081179091556040518581527fe139be2fc520b685c93d718b643b5d8c42fc57b5724201180c5d765635467312906020015b60405180910390a250505050565b60865460ff16156131d65760405162461bcd60e51b8152600401610cb590615b50565b33836131e282826135a1565b6131fe5760405162461bcd60e51b8152600401610cb590615be3565b6000858152601a60209081526040808320815160808101835281548152600182015493810193909352600281015491830191909152600301546060820152906132456137e6565b50905060008061325689858561386b565b915091508060001415611e1f57600e546020850151429161328891600160801b9091046001600160401b031690615c52565b11156132bb5760405162461bcd60e51b8152602060048201526002602482015261333160f01b6044820152606401610cb5565b6132c5898561420e565b60006132e08386606001516132db6001546147ce565b614269565b509050878110156133185760405162461bcd60e51b8152602060048201526002602482015261199960f11b6044820152606401610cb5565b604080518b8152602081018390527f2f06d076c30d294b959d7aa34f40d448e45f487492a47889f02831bb06fee6bf910160405180910390a1612e738982613d67565b600080516020615faa83398151915261337481336138f0565b81633b9aca00816001600160401b031611156133b65760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610cb5565b6133c08385615dd4565b6001600160401b03166133d86002633b9aca00615d0a565b116134095760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610cb5565b600d80546001600160801b031916600160401b6001600160401b0387811691820267ffffffffffffffff1916929092179186169182179092556040805192835260208301919091527fb556fe5cb4a1a8243b8d5000bbefd6f8b868adcac2765cd4a30ac9320ff1a0b6910160405180910390a150505050565b6000818152601d60205260409020546001600160a01b0316806134cb5760405162461bcd60e51b81526020600482015260016024820152601960f91b6044820152606401610cb5565b919050565b6000818152601f6020526040902080546001600160a01b0319166001600160a01b038416908117909155819061350582613482565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6040516001600160a01b038316602482015260448101829052610d8d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526148c7565b6000806135ad83613482565b9050806001600160a01b0316846001600160a01b031614806135e857506000838152601f60205260409020546001600160a01b038581169116145b8061361657506001600160a01b038082166000908152602080805260408083209388168352929052205460ff165b949350505050565b61362882826140b0565b6000828152601c60205260409020548015610d8d576000838152601c60209081526040808320839055601d9091529020546005546001600160a01b03918216916136749116828461353e565b806001600160a01b03167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486836040516131a591815260200190565b826001600160a01b03166136c282613482565b6001600160a01b0316146136e85760405162461bcd60e51b8152600401610cb590615bc8565b6001600160a01b0382166137235760405162461bcd60e51b8152602060048201526002602482015261191b60f11b6044820152606401610cb5565b61372e6000826134d0565b6001600160a01b0383166000908152601e60205260408120805460019290613757908490615e03565b90915550506001600160a01b0382166000908152601e60205260408120805460019290613785908490615c52565b90915550506000818152601d602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600354604080516341f654f760e01b8152815160009384936001600160a01b03909116926341f654f79260048083019392829003018186803b15801561382b57600080fd5b505afa15801561383f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613863919061569e565b915091509091565b600080600080600061387d8787614726565b9150915081600014806138905750806001145b156138a45761389f888861420e565b600192505b50925090505b935093915050565b6040516001600160a01b03808516602483015283166044820152606481018290526138ea9085906323b872dd60e01b9060840161356a565b50505050565b60008281526022602090815260408083206001600160a01b038516845290915290205460ff166110da5761392e816001600160a01b03166014614999565b613939836020614999565b60405160200161394a92919061598c565b60408051601f198184030181529082905262461bcd60e51b8252610cb591600401615b3d565b60008281526022602090815260408083206001600160a01b038516845290915290205460ff166110da5760008281526022602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008281526022602090815260408083206001600160a01b038516845290915290205460ff16156110da5760008281526022602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600060015460001415613a8c575060175490565b600154670de0b6b3a7640000601454601654613aa6614b34565b613ab09190615e03565b613aba9190615db5565b613ac49190615db5565b613ace9190615c95565b601754613adb9190615c52565b905090565b60865460ff16613b295760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610cb5565b6086805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b602154610100900460ff1680613b8c575060215460ff16155b613ba85760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015613bca576021805461ffff19166101011790555b613bd2614b4f565b613bda614bb9565b801561152e576021805461ff001916905550565b602154610100900460ff1680613c07575060215460ff16155b613c235760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015613c45576021805461ffff19166101011790555b613bda614b4f565b6110da8282613970565b600082815260226020526040902060010154819060405184907fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff90600090a460009182526022602052604090912060010155565b60865460ff1615613cce5760405162461bcd60e51b8152600401610cb590615b50565b6086805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613b563390565b6000828152601c60209081526040808320548354601b90935290832054909190670de0b6b3a764000090613d35613a78565b613d3f9190615e03565b613d499086615db5565b613d539190615c95565b613d5d9190615c95565b6115589190615c52565b60065460408051629032ff60e51b815290516000926001600160a01b0316916312065fe0916004808301926020929190829003018186803b158015613dab57600080fd5b505afa158015613dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de3919061563c565b9050818110158015613df55750600082115b15613e1857600654600854610d8d916001600160a01b03918216911685856138b2565b8115610d8d576000613e2a8284615e03565b600654600854919250613e4b916001600160a01b03908116911686856138b2565b600754604051631a115ff160e01b8152600481018390526001600160a01b03868116602483015290911690631a115ff190604401600060405180830381600087803b158015613e9957600080fd5b505af1158015613ead573d6000803e3d6000fd5b5050505050505050565b600e54600090633b9aca0090613edd90600160c01b90046001600160401b031684615db5565b613ee79190615c95565b9050600f5481106134cb57600f54610c6b565b600080613f1384600154613f0e9190615c52565b6147ce565b9050633b9aca006001600160401b03821610613f565760405162461bcd60e51b8152602060048201526002602482015261323560f01b6044820152606401610cb5565b6000633b9aca00614042836009805480602002602001604051908101604052809291908181526020018280548015613fdf57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411613f9c5790505b5050505050600a805480602002602001604051908101604052809291908181526020018280548015612cc657600091825260209182902080546001600160401b03168452908202830192909160089101808411612c8357905050505050506143dd565b600e5461405891906001600160401b0316615dd4565b6001600160401b031661406b9190615c95565b9050633b9aca0061407c8282615e03565b6140869086615db5565b6140909190615c95565b61409a9085615e03565b90506140a68187615e03565b9695505050505050565b6140b8613a78565b6017556140c3614b34565b6016556140d08282613d03565b6000928352601c6020908152604080852092909255601754601b90915292209190915550565b6001600160a01b0382166000908152601e6020526040812080546001929061411f908490615c52565b90915550506000818152601d602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46141956000838360405180602001604052806000815250614c2e565b6110da5760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610cb5565b6141d18484846136af565b6141dd84848484614c2e565b6138ea5760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610cb5565b8051606082015160009161422191615db5565b905061422d838261361e565b6000838152601b60205260408120819055546142499082615c95565b6001600082825461425a9190615e03565b90915550610d8d905083614d50565b600080633b9aca0061435684600b8054806020026020016040519081016040528092919081815260200182805480156142f357602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116142b05790505b5050505050600c805480602002602001604051908101604052809291908181526020018280548015612cc657600091825260209182902080546001600160401b03168452908202830192909160089101808411612c8357905050505050506143dd565b600e546143739190600160401b90046001600160401b0316615dd4565b6001600160401b03166143869190615c95565b9050633b9aca006143978282615e03565b6143a19086615db5565b6143ab9190615c95565b6143b59085615e03565b90508481106143c9575060009050836138aa565b6143d38186615e03565b9150935093915050565b600082600184516143ee9190615e03565b815181106143fe576143fe615f15565b60200260200101516001600160401b0316846001600160401b03161061444c57816001845161442d9190615e03565b8151811061443d5761443d615f15565b60200260200101519050611558565b8260008151811061445f5761445f615f15565b60200260200101516001600160401b0316846001600160401b031611614492578160008151811061443d5761443d615f15565b600080600185516144a39190615e03565b905060005b60016144b48484615e03565b111561451e5760026144c68484615e03565b6144d09190615c95565b6144da9084615c52565b9050866001600160401b03168682815181106144f8576144f8615f15565b60200260200101516001600160401b031611614516578092506144a8565b8091506144a8565b84838151811061453057614530615f15565b60200260200101516001600160401b031685838151811061455357614553615f15565b60200260200101516001600160401b0316111561464d5785838151811061457c5761457c615f15565b602002602001015186838151811061459657614596615f15565b60200260200101516145a89190615e1a565b8684815181106145ba576145ba615f15565b6020026020010151886145cd9190615e1a565b8685815181106145df576145df615f15565b60200260200101518785815181106145f9576145f9615f15565b602002602001015161460b9190615e1a565b6146159190615dd4565b61461f9190615ca9565b85848151811061463157614631615f15565b60200260200101516146439190615c6a565b9350505050611558565b85838151811061465f5761465f615f15565b602002602001015186838151811061467957614679615f15565b602002602001015161468b9190615e1a565b86848151811061469d5761469d615f15565b6020026020010151886146b09190615e1a565b8684815181106146c2576146c2615f15565b60200260200101518786815181106146dc576146dc615f15565b60200260200101516146ee9190615e1a565b6146f89190615dd4565b6147029190615ca9565b85848151811061471457614714615f15565b60200260200101516146439190615e1a565b600080600083856000015186606001516147409190615db5565b61474a9190615c95565b9050846040015185606001516147609190615c52565b811061476f57600092506147c6565b80856040015186606001516147849190615c52565b61478e9190615e03565b600d5460608701519194506147ae916001600160401b0390911690615db5565b6147bc633b9aca0085615db5565b116147c657600191505b509250929050565b600080633b9aca00600d60109054906101000a90046001600160401b03166001600160401b0316600760009054906101000a90046001600160a01b03166001600160a01b031663344844db6040518163ffffffff1660e01b815260040160206040518083038186803b15801561484357600080fd5b505afa158015614857573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061487b919061563c565b6148859190615db5565b61488f9190615c95565b9050808310156148b957806148a8633b9aca0085615db5565b6148b29190615c95565b91506148c1565b633b9aca0091505b50919050565b600061491c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e0c9092919063ffffffff16565b805190915015610d8d578080602001905181019061493a919061555f565b610d8d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610cb5565b606060006149a8836002615db5565b6149b3906002615c52565b6001600160401b038111156149ca576149ca615f2b565b6040519080825280601f01601f1916602001820160405280156149f4576020820181803683370190505b509050600360fc1b81600081518110614a0f57614a0f615f15565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614a3e57614a3e615f15565b60200101906001600160f81b031916908160001a9053506000614a62846002615db5565b614a6d906001615c52565b90505b6001811115614ae5576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614aa157614aa1615f15565b1a60f81b828281518110614ab757614ab7615f15565b60200101906001600160f81b031916908160001a90535060049490941c93614ade81615e6e565b9050614a70565b5083156115585760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610cb5565b6000806013544210614b4857601354610c6b565b4292915050565b602154610100900460ff1680614b68575060215460ff16155b614b845760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015613bda576021805461ffff1916610101179055801561152e576021805461ff001916905550565b602154610100900460ff1680614bd2575060215460ff16155b614bee5760405162461bcd60e51b8152600401610cb590615b7a565b602154610100900460ff16158015614c10576021805461ffff19166101011790555b6086805460ff19169055801561152e576021805461ff001916905550565b60006001600160a01b0384163b15614d4557604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614c72903390899088908890600401615a01565b602060405180830381600087803b158015614c8c57600080fd5b505af1925050508015614cbc575060408051601f3d908101601f19168201909252614cb9918101906155d7565b60015b614d2b573d808015614cea576040519150601f19603f3d011682016040523d82523d6000602084013e614cef565b606091505b508051614d235760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610cb5565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050613616565b506001949350505050565b6000614d5b82613482565b9050614d686000836134d0565b6001600160a01b0381166000908152601e60205260408120805460019290614d91908490615e03565b90915550506000828152601d6020908152604080832080546001600160a01b0319169055601a9091528082208281556001810183905560028101839055600301829055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6060613616848460008585843b614e655760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cb5565b600080866001600160a01b03168587604051614e8191906158d2565b60006040518083038185875af1925050503d8060008114614ebe576040519150601f19603f3d011682016040523d82523d6000602084013e614ec3565b606091505b5091509150614ed3828286614ede565b979650505050505050565b60608315614eed575081611558565b825115614efd5782518084602001fd5b8160405162461bcd60e51b8152600401610cb59190615b3d565b82805482825590600052602060002090600301600490048101928215614fbf5791602002820160005b83821115614f8a57835183826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302614f40565b8015614fbd5782816101000a8154906001600160401b030219169055600801602081600701049283019260010302614f8a565b505b50614fcb929150615043565b5090565b828054614fdb90615e85565b90600052602060002090601f016020900481019282614ffd5760008555614fbf565b82601f1061501657805160ff1916838001178555614fbf565b82800160010185558215614fbf579182015b82811115614fbf578251825591602001919060010190615028565b5b80821115614fcb5760008155600101615044565b60006001600160401b0383111561507157615071615f2b565b615084601f8401601f1916602001615bff565b905082815283838301111561509857600080fd5b828260208301376000602084830101529392505050565b80356134cb81615f41565b600082601f8301126150cb57600080fd5b813560206150e06150db83615c2f565b615bff565b80838252828201915082860187848660051b890101111561510057600080fd5b60005b858110156151265761511482615133565b84529284019290840190600101615103565b5090979650505050505050565b80356001600160401b03811681146134cb57600080fd5b60006020828403121561515c57600080fd5b813561155881615f41565b60006020828403121561517957600080fd5b815161155881615f41565b6000806040838503121561519757600080fd5b82356151a281615f41565b915060208301356151b281615f41565b809150509250929050565b6000806000606084860312156151d257600080fd5b83356151dd81615f41565b925060208401356151ed81615f41565b929592945050506040919091013590565b6000806000806080858703121561521457600080fd5b843561521f81615f41565b9350602085013561522f81615f41565b92506040850135915060608501356001600160401b0381111561525157600080fd5b8501601f8101871361526257600080fd5b61527187823560208401615058565b91505092959194509250565b6000806040838503121561529057600080fd5b823561529b81615f41565b915060208301356151b281615f56565b600080604083850312156152be57600080fd5b82356152c981615f41565b946020939093013593505050565b600080600080600060a086880312156152ef57600080fd5b85356152fa81615f41565b97602087013597506040870135966060810135965060800135945092505050565b6000806000806080858703121561533157600080fd5b84356001600160401b0381111561534757600080fd5b8501601f8101871361535857600080fd5b803560206153686150db83615c2f565b8083825282820191508285018b848660051b880101111561538857600080fd5b600095505b848610156153b45780356153a081615f41565b83526001959095019491830191830161538d565b5097506153c490508882016150af565b95505050506153d5604086016150af565b91506153e3606086016150af565b905092959194509250565b6000602080838503121561540157600080fd5b82356001600160401b0381111561541757600080fd5b8301601f8101851361542857600080fd5b80356154366150db82615c2f565b80828252848201915084840188868560051b870101111561545657600080fd5b600094505b8385101561547957803583526001949094019391850191850161545b565b50979650505050505050565b6000806040838503121561549857600080fd5b82356001600160401b03808211156154af57600080fd5b6154bb868387016150ba565b935060208501359150808211156154d157600080fd5b506154de858286016150ba565b9150509250929050565b6000806000606084860312156154fd57600080fd5b83356001600160401b038082111561551457600080fd5b615520878388016150ba565b9450602086013591508082111561553657600080fd5b50615543868287016150ba565b925050604084013561555481615f7a565b809150509250925092565b60006020828403121561557157600080fd5b815161155881615f56565b60006020828403121561558e57600080fd5b5035919050565b600080604083850312156155a857600080fd5b8235915060208301356151b281615f41565b6000602082840312156155cc57600080fd5b813561155881615f64565b6000602082840312156155e957600080fd5b815161155881615f64565b60006020828403121561560657600080fd5b81356001600160401b0381111561561c57600080fd5b8201601f8101841361562d57600080fd5b61361684823560208401615058565b60006020828403121561564e57600080fd5b5051919050565b60008060006060848603121561566a57600080fd5b8335925060208401356151ed81615f41565b6000806040838503121561568f57600080fd5b50508035926020909101359150565b600080604083850312156156b157600080fd5b505080516020909101519092909150565b6000806000606084860312156156d757600080fd5b8335925060208401359150604084013561555481615f41565b60006020828403121561570257600080fd5b61155882615133565b6000806040838503121561571e57600080fd5b61572783615133565b915061573560208401615133565b90509250929050565b60006020828403121561575057600080fd5b815161155881615f7a565b600081518084526020808501945080840160005b838110156157945781516001600160401b03168752958201959082019060010161576f565b509495945050505050565b805480835260008281526020808220940193909190825b826003820110156158055781546001600160401b038082168852604082811c821660208a0152608083811c9092169089015260c09190911c6060880152909501946001909101906004016157b6565b90549082811015615826576001600160401b03821686526020909501946001015b82811015615848576001600160401b03604083901c1686526020909501946001015b8281101561586a576001600160401b03608083901c1686526020909501946001015b828110156158805760c082901c86526020860195505b5093949350505050565b600081518084526158a2816020860160208601615e42565b601f01601f19169290920160200192915050565b600081516158c8818560208601615e42565b9290920192915050565b600082516158e4818460208701615e42565b9190910192915050565b600080845481600182811c91508083168061590a57607f831692505b602080841082141561592a57634e487b7160e01b86526022600452602486fd5b81801561593e576001811461594f5761597c565b60ff1986168952848901965061597c565b60008b81526020902060005b868110156159745781548b82015290850190830161595b565b505084890196505b50505050505061305d81856158b6565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516159c4816017850160208801615e42565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516159f5816028840160208801615e42565b01602801949350505050565b60006001600160a01b038087168352808616602084015250836040830152608060608301526140a6608083018461588a565b6080808252855190820181905260009060209060a0840190828901845b82811015615a6c57815184529284019290840190600101615a50565b5050508381038285015286518082528783019183019060005b81811015615ab557835180516001600160a01b031684528501518584015292840192604090920191600101615a85565b50506001600160a01b03871660408601529250615ad0915050565b82606083015295945050505050565b606081526000615af2606083018661575b565b8281036020840152615b04818661575b565b91505060ff83166040830152949350505050565b604081526000615b2b604083018561579f565b828103602084015261305d818561579f565b602081526000611558602083018461588a565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600190820152603160f81b604082015260600190565b602080825260029082015261323160f01b604082015260600190565b604051601f8201601f191681016001600160401b0381118282101715615c2757615c27615f2b565b604052919050565b60006001600160401b03821115615c4857615c48615f2b565b5060051b60200190565b60008219821115615c6557615c65615ee9565b500190565b60006001600160401b03808316818516808303821115615c8c57615c8c615ee9565b01949350505050565b600082615ca457615ca4615eff565b500490565b60006001600160401b0380841680615cc357615cc3615eff565b92169190910492915050565b600181815b808511156147c6578160001904821115615cf057615cf0615ee9565b80851615615cfd57918102915b93841c9390800290615cd4565b600061155860ff841683600082615d2357506001610c6b565b81615d3057506000610c6b565b8160018114615d465760028114615d5057615d6c565b6001915050610c6b565b60ff841115615d6157615d61615ee9565b50506001821b610c6b565b5060208310610133831016604e8410600b8410161715615d8f575081810a610c6b565b615d998383615ccf565b8060001904821115615dad57615dad615ee9565b029392505050565b6000816000190483118215151615615dcf57615dcf615ee9565b500290565b60006001600160401b0380831681851681830481118215151615615dfa57615dfa615ee9565b02949350505050565b600082821015615e1557615e15615ee9565b500390565b60006001600160401b0383811690831681811015615e3a57615e3a615ee9565b039392505050565b60005b83811015615e5d578181015183820152602001615e45565b838111156138ea5750506000910152565b600081615e7d57615e7d615ee9565b506000190190565b600181811c90821680615e9957607f821691505b602082108114156148c157634e487b7160e01b600052602260045260246000fd5b6000600019821415615ece57615ece615ee9565b5060010190565b600082615ee457615ee4615eff565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461152e57600080fd5b801515811461152e57600080fd5b6001600160e01b03198116811461152e57600080fd5b60ff8116811461152e57600080fdfe5916f72c85af4ac6f7e34636ecc97619c4b2085da099a5d28f3e58436cfbe56255435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a264697066735822122045840058006f230868797238b1a0691e6a0b163718211cd780d1fcfd01a5532c64736f6c63430008070033

Deployed Bytecode Sourcemap

129868:29978:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;159197:646;;;;;;:::i;:::-;;:::i;:::-;;;22924:14:1;;22917:22;22899:41;;22887:2;22872:18;159197:646:0;;;;;;;;153295:100;153369:18;;;;;;;;;;;;-1:-1:-1;;;153369:18:0;;;;153295:100;;;;;;;:::i;155924:179::-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;18944:55:1;;;18926:74;;18914:2;18899:18;155924:179:0;18780:226:1;155511:283:0;;;;;;:::i;:::-;;:::i;:::-;;86226:40;;;;;-1:-1:-1;;;86226:40:0;;-1:-1:-1;;;;;86226:40:0;;;;;;-1:-1:-1;;;;;36295:31:1;;;36277:50;;36265:2;36250:18;86226:40:0;36133:200:1;112864:72:0;;-1:-1:-1;;;;;;;;;;;112864:72:0;;;;;23097:25:1;;;23085:2;23070:18;112864:72:0;22951:177:1;85890:22:0;;;;;-1:-1:-1;;;85890:22:0;;-1:-1:-1;;;;;85890:22:0;;;117194:340;;;;;;:::i;:::-;;:::i;83077:30::-;;;;;;:::i;:::-;;:::i;152884:233::-;;;;;;:::i;:::-;;:::i;157477:217::-;;;;;;:::i;:::-;;:::i;45599:123::-;;;;;;:::i;:::-;45665:7;45692:12;;;:6;:12;;;;;:22;;;;45599:123;139640:657;;;;;;:::i;:::-;;:::i;112746:66::-;;-1:-1:-1;;;;;;;;;;;112746:66:0;;45984:141;;;;;;:::i;:::-;;:::i;84628:26::-;;;;;-1:-1:-1;;;84628:26:0;;-1:-1:-1;;;;;84628:26:0;;;47020:165;;;;;;:::i;:::-;;:::i;121648:162::-;;;;;;:::i;:::-;;:::i;127339:445::-;;;;;;:::i;:::-;;:::i;87334:34::-;;;;;;:::i;:::-;;:::i;87863:30::-;;;;;;115584:1290;;;;;;:::i;:::-;;:::i;119682:90::-;;;:::i;87978:34::-;;;;;-1:-1:-1;;;;;87978:34:0;;;157937:187;;;;;;:::i;:::-;;:::i;157091:169::-;;;;;;:::i;:::-;;:::i;128268:137::-;;;;;;:::i;:::-;;:::i;126394:376::-;;;;;;:::i;:::-;;:::i;130932:1463::-;;;;;;:::i;:::-;;:::i;83226:31::-;;;;;;:::i;:::-;;:::i;152448:198::-;;;;;;:::i;:::-;;:::i;124805:578::-;;;;;;:::i;:::-;;:::i;121142:154::-;;;;;;:::i;:::-;;:::i;4368:86::-;4439:7;;;;4368:86;;154907:126;;;;;;:::i;:::-;;:::i;88170:21::-;;;:::i;140841:1853::-;;;;;;:::i;:::-;;:::i;154621:161::-;;;;;;:::i;:::-;;:::i;128819:150::-;;;;;;:::i;:::-;;:::i;87831:25::-;;;;;;143469:1159;;;;;;:::i;:::-;;:::i;86520:39::-;;;;;;81376:21;;;;;-1:-1:-1;;;;;81376:21:0;;;123777:494;;;;;;:::i;:::-;;:::i;88499:62::-;;;;;;:::i;:::-;;;;;;;;;;;;;;119548:86;;;:::i;118173:232::-;;;;;;:::i;:::-;;:::i;86952:35::-;;;;;;84396:27;;;;;-1:-1:-1;;;84396:27:0;;-1:-1:-1;;;;;84396:27:0;;;85539:34;;;;;-1:-1:-1;;;85539:34:0;;-1:-1:-1;;;;;85539:34:0;;;44462:139;;;;;;:::i;:::-;44540:4;44564:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;44564:29:0;;;;;;;;;;;;;;;44462:139;72421:43;;72459:5;72421:43;;42718:49;;42763:4;42718:49;;156350:260;;;;;;:::i;:::-;;:::i;133487:2628::-;;;;;;:::i;:::-;;:::i;83949:25::-;;;;;-1:-1:-1;;;83949:25:0;;-1:-1:-1;;;;;83949:25:0;;;114512:575;;;;;;:::i;:::-;;:::i;125633:358::-;;;;;;:::i;:::-;;:::i;158374:259::-;;;;;;:::i;:::-;;:::i;80895:31::-;;;;;;145393:6026;;;;;;:::i;:::-;;:::i;85140:33::-;;;;;-1:-1:-1;;;;;85140:33:0;;;82847:30;;;;;;:::i;:::-;;:::i;118949:234::-;;;;;;:::i;:::-;;:::i;153695:752::-;;;;;;:::i;:::-;;:::i;87900:29::-;;;;;;87491:34;;;;;;:::i;:::-;;:::i;46370:143::-;;;;;;:::i;:::-;;:::i;83692:31::-;;;;;-1:-1:-1;;;;;83692:31:0;;;83317;;;;;;:::i;:::-;;:::i;82036:::-;;;;;-1:-1:-1;;;;;82036:31:0;;;87936:35;;;;;;72217:44;;72255:6;72217:44;;151975:237;;;;;;:::i;:::-;;:::i;:::-;;;;35658:25:1;;;35714:2;35699:18;;35692:34;;;;35631:18;151975:237:0;35484:248:1;120545:378:0;;;;;;:::i;:::-;;:::i;137188:1759::-;;;;;;:::i;:::-;;:::i;156803:156::-;;;;;;:::i;:::-;-1:-1:-1;;;;;156916:25:0;;;156892:4;156916:25;;;:18;:25;;;;;;;:35;;;;;;;;;;;;;;;156803:156;87797:27;;;;;;88700:42;;;;;;:::i;:::-;;;;;;;;;;;;;;122339:496;;;;;;:::i;:::-;;:::i;81947:25::-;;;;;-1:-1:-1;;;;;81947:25:0;;;88350:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35968:25:1;;;36024:2;36009:18;;36002:34;;;;36052:18;;;36045:34;36110:2;36095:18;;36088:34;35955:3;35940:19;88350:50:0;35737:391:1;159197:646:0;159285:4;-1:-1:-1;;;;;;159322:55:0;;-1:-1:-1;;;159322:55:0;;:131;;-1:-1:-1;;;;;;;159394:59:0;;-1:-1:-1;;;159394:59:0;159322:131;:196;;;-1:-1:-1;;;;;;;159470:48:0;;-1:-1:-1;;;159470:48:0;159322:196;:270;;;-1:-1:-1;;;;;;;159535:57:0;;-1:-1:-1;;;159535:57:0;159322:270;:334;;;-1:-1:-1;;;;;;;159609:47:0;;-1:-1:-1;;;159609:47:0;159322:334;:399;;;-1:-1:-1;;;;;;;159673:48:0;;-1:-1:-1;;;159673:48:0;159322:399;:456;;;-1:-1:-1;;;;;;;159738:40:0;;-1:-1:-1;;;159738:40:0;159322:456;:513;;;-1:-1:-1;;;;;;;159795:40:0;;-1:-1:-1;;;159795:40:0;159322:513;159302:533;159197:646;-1:-1:-1;;159197:646:0:o;155924:179::-;155998:7;107756:20;;;:7;:20;;;;;;-1:-1:-1;;;;;107756:20:0;156018:34;;;;-1:-1:-1;;;156018:34:0;;31468:2:1;156018:34:0;;;31450:21:1;31507:1;31487:18;;;31480:29;-1:-1:-1;;;31525:18:1;;;31518:31;31566:18;;156018:34:0;;;;;;;;;106142:7;106169:32;;;:19;:32;;;;;;-1:-1:-1;;;;;106169:32:0;156070:25;106076:133;155511:283;155590:13;155606:21;155615:11;155606:8;:21::i;:::-;155590:37;;155652:5;-1:-1:-1;;;;;155646:11:0;:2;-1:-1:-1;;;;;155646:11:0;;;155638:26;;;;-1:-1:-1;;;155638:26:0;;27408:2:1;155638:26:0;;;27390:21:1;27447:1;27427:18;;;27420:29;-1:-1:-1;;;27465:18:1;;;27458:32;27507:18;;155638:26:0;27206:325:1;155638:26:0;155683:10;-1:-1:-1;;;;;155683:19:0;;;;:58;;-1:-1:-1;;;;;;156916:25:0;;156892:4;156916:25;;;:18;:25;;;;;;;155730:10;156916:35;;;;;;;;;;155706;155675:73;;;;-1:-1:-1;;;155675:73:0;;;;;;;:::i;:::-;155761:25;155770:2;155774:11;155761:8;:25::i;:::-;155579:215;155511:283;;:::o;117194:340::-;113726:19;;-1:-1:-1;;;;;113726:19:0;113712:10;:33;113704:47;;;;-1:-1:-1;;;113704:47:0;;;;;;;:::i;:::-;117390:11:::1;::::0;-1:-1:-1;;;;;117366:36:0;;::::1;117390:11:::0;::::1;117366:36;;117358:51;;;::::0;-1:-1:-1;;;117358:51:0;;28413:2:1;117358:51:0::1;::::0;::::1;28395:21:1::0;28452:1;28432:18;;;28425:29;-1:-1:-1;;;28470:18:1;;;28463:32;28512:18;;117358:51:0::1;28211:325:1::0;117358:51:0::1;117420:50;-1:-1:-1::0;;;;;117420:33:0;::::1;117454:2:::0;117458:11;117420:33:::1;:50::i;:::-;117510:2;-1:-1:-1::0;;;;;117486:40:0::1;117496:12;-1:-1:-1::0;;;;;117486:40:0::1;;117514:11;117486:40;;;;23097:25:1::0;;23085:2;23070:18;;22951:177;117486:40:0::1;;;;;;;;117194:340:::0;;;:::o;83077:30::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;83077:30:0;;:::o;152884:233::-;4439:7;;;;4693:9;4685:38;;;;-1:-1:-1;;;4685:38:0;;;;;;;:::i;:::-;152967:10:::1;152979:11;113502:39;113521:6;113529:11;113502:18;:39::i;:::-;113494:54;;;;-1:-1:-1::0;;;113494:54:0::1;;;;;;;:::i;:::-;153072:26:::2;::::0;;;:13:::2;:26;::::0;;;;:36;;153027:42:::2;::::0;;::::2;::::0;153003:106:::2;::::0;153014:11;;153027:81:::2;::::0;153072:36;153027:81:::2;:::i;:::-;153003:10;:106::i;157477:217::-:0;157618:10;157630:11;113502:39;113521:6;113529:11;113502:18;:39::i;:::-;113494:54;;;;-1:-1:-1;;;113494:54:0;;;;;;;:::i;:::-;157654:32:::1;157664:4;157670:2;157674:11;157654:9;:32::i;:::-;157477:217:::0;;;;;:::o;139640:657::-;4439:7;;;;4693:9;4685:38;;;;-1:-1:-1;;;4685:38:0;;;;;;;:::i;:::-;139808:26:::1;139837::::0;;;:13:::1;:26;::::0;;;;;;;139808:55;;::::1;::::0;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;;;;;::::1;;::::0;;;;;;139897:17:::1;:15;:17::i;:::-;139874:40;;;139928:18;139950:51;139968:11;139981:9;139992:8;139950:17;:51::i;:::-;139925:76:::0;-1:-1:-1;;140016:15:0;140012:278:::1;;140123:11;::::0;140079:6:::1;::::0;:65:::1;::::0;-1:-1:-1;;;;;140079:6:0;;::::1;::::0;140103:10:::1;::::0;140123:11:::1;140137:6:::0;140079:23:::1;:65::i;:::-;140159:26;::::0;;;:13:::1;:26;::::0;;;;:33:::1;;:43:::0;;140196:6;;140159:26;:43:::1;::::0;140196:6;;140159:43:::1;:::i;:::-;;;;;;;;140222:56;140239:11;140271:6;140252:9;:16;;;:25;;;;:::i;:::-;140222:56;::::0;;35658:25:1;;;35714:2;35699:18;;35692:34;;;;35631:18;140222:56:0::1;;;;;;;;139733:564;;;139640:657:::0;;:::o;45984:141::-;45665:7;45692:12;;;:6;:12;;;;;:22;;;44322:28;44333:4;44339:10;44322;:28::i;:::-;46092:25:::1;46103:4;46109:7;46092:10;:25::i;47020:165::-:0;-1:-1:-1;;;;;47110:21:0;;47121:10;47110:21;47102:36;;;;-1:-1:-1;;;47102:36:0;;25682:2:1;47102:36:0;;;25664:21:1;25721:1;25701:18;;;25694:29;-1:-1:-1;;;25739:18:1;;;25732:32;25781:18;;47102:36:0;25480:325:1;47102:36:0;47151:26;47163:4;47169:7;47151:11;:26::i;:::-;47020:165;;:::o;121648:162::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;121740:8:::1;:20:::0;;-1:-1:-1;;;;121740:20:0::1;-1:-1:-1::0;;;;;;;;121740:20:0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;121776:26:::1;::::0;36277:50:1;;;121776:26:0::1;::::0;36265:2:1;36250:18;121776:26:0::1;;;;;;;;121648:162:::0;;:::o;127339:445::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;127547:19:::1;127568;75480:6;:13;75463:6;:13;:30;:51;;;;;75513:1;75497:6;:13;:17;75463:51;75455:65;;;::::0;-1:-1:-1;;;75455:65:0;;32814:2:1;75455:65:0::1;::::0;::::1;32796:21:1::0;32853:1;32833:18;;;32826:29;-1:-1:-1;;;32871:18:1;;;32864:31;32912:18;;75455:65:0::1;32612:324:1::0;75455:65:0::1;75536:9;75531:257;75572:1;75556:6;:13;:17;;;;:::i;:::-;75551:1;:22;75531:257;;72459:5;-1:-1:-1::0;;;;;75603:32:0::1;:6;75610:1;75603:9;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;75603:32:0::1;;;:68;;;;;72459:5;-1:-1:-1::0;;;;;75639:32:0::1;:6;75646:1;75639:9;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;75639:32:0::1;;;75603:68;75595:82;;;::::0;-1:-1:-1;;;75595:82:0;;33884:2:1;75595:82:0::1;::::0;::::1;33866:21:1::0;33923:1;33903:18;;;33896:29;-1:-1:-1;;;33941:18:1;;;33934:31;33982:18;;75595:82:0::1;33682:324:1::0;75595:82:0::1;75696:5:::0;;75692:85:::1;;75742:6:::0;75749:5:::1;75753:1;75749::::0;:5:::1;:::i;:::-;75742:13;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;75730:25:0::1;:6;75737:1;75730:9;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;75730:25:0::1;;75722:39;;;::::0;-1:-1:-1;;;75722:39:0;;26342:2:1;75722:39:0::1;::::0;::::1;26324:21:1::0;26381:1;26361:18;;;26354:29;-1:-1:-1;;;26399:18:1;;;26392:31;26440:18;;75722:39:0::1;26140:324:1::0;75722:39:0::1;75575:3:::0;::::1;::::0;::::1;:::i;:::-;;;;75531:257;;;-1:-1:-1::0;127605:40:0;;::::2;::::0;:18:::2;::::0;:40:::2;::::0;::::2;::::0;::::2;:::i;:::-;-1:-1:-1::0;127656:40:0;;::::2;::::0;:18:::2;::::0;:40:::2;::::0;::::2;::::0;::::2;:::i;:::-;;127712:64;127737:18;127757;127712:64;;;;;;;:::i;87334:34::-:0;;;;;;;;;;;;115584:1290;113726:19;;-1:-1:-1;;;;;113726:19:0;113712:10;:33;113704:47;;;;-1:-1:-1;;;113704:47:0;;;;;;;:::i;:::-;115704:17:::1;:15;:17::i;:::-;115681:20;:40:::0;115757:12:::1;::::0;115738:15:::1;:31;115734:476;;115880:15;::::0;115871:24:::1;::::0;:6;:24:::1;:::i;:::-;115858:10;:37:::0;115734:476:::1;;;115928:17;115963:15;115948:12;;:30;;;;:::i;:::-;115928:50;;115993:16;116024:10;;116012:9;:22;;;;:::i;:::-;116183:15;::::0;115993:41;;-1:-1:-1;116162:17:0::1;115993:41:::0;116162:6;:17:::1;:::i;:::-;116161:37;;;;:::i;:::-;116148:10;:50:::0;-1:-1:-1;;115734:476:0::1;116592:11;::::0;:36:::1;::::0;-1:-1:-1;;;116592:36:0;;116622:4:::1;116592:36;::::0;::::1;18926:74:1::0;116574:15:0::1;::::0;-1:-1:-1;;;;;116592:11:0::1;::::0;:21:::1;::::0;18899:18:1;;116592:36:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;116574:54;;116673:15;;116663:7;:25;;;;:::i;:::-;116649:10;;:39;;116641:54;;;::::0;-1:-1:-1;;;116641:54:0;;33143:2:1;116641:54:0::1;::::0;::::1;33125:21:1::0;33182:1;33162:18;;;33155:29;-1:-1:-1;;;33200:18:1;;;33193:32;33242:18;;116641:54:0::1;32941:325:1::0;116641:54:0::1;116725:15;116708:14;:32:::0;;;116816:15:::1;::::0;116798:33:::1;::::0;::::1;:::i;:::-;116783:12;:48:::0;116847:19:::1;::::0;23097:25:1;;;116847:19:0::1;::::0;23085:2:1;23070:18;116847:19:0::1;22951:177:1::0;119682:90:0;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;119754:10:::1;:8;:10::i;:::-;119682:90:::0;:::o;157937:187::-;158073:43;158090:4;158096:2;158100:11;158073:43;;;;;;;;;;;;:16;:43::i;157091:169::-;157188:4;157212:40;157231:7;157240:11;157212:18;:40::i;:::-;157205:47;157091:169;-1:-1:-1;;;157091:169:0:o;128268:137::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;-1:-1:-1;128372:11:0::1;:25:::0;;-1:-1:-1;;;;;;128372:25:0::1;-1:-1:-1::0;;;;;128372:25:0;;;::::1;::::0;;;::::1;::::0;;128268:137::o;126394:376::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;126571:24:::1;:52:::0;;;126634:20:::1;:44:::0;;;126694:68:::1;::::0;;35658:25:1;;;35714:2;35699:18;;35692:34;;;126694:68:0::1;::::0;35631:18:1;126694:68:0::1;;;;;;;;126394:376:::0;;;:::o;130932:1463::-;1592:13;;;;;;;;:30;;-1:-1:-1;1610:12:0;;;;1609:13;1592:30;1584:89;;;;-1:-1:-1;;;1584:89:0;;;;;;;:::i;:::-;1709:13;;;;;;;1708:14;1733:101;;;;1768:13;:20;;-1:-1:-1;;1803:19:0;;;;;1733:101;131066:12;-1:-1:-1;;;;;76413:24:0;::::1;76405:38;;;::::0;-1:-1:-1;;;76405:38:0;;24314:2:1;76405:38:0::1;::::0;::::1;24296:21:1::0;24353:1;24333:18;;;24326:29;-1:-1:-1;;;24371:18:1;;;24364:31;24412:18;;76405:38:0::1;24112:324:1::0;76405:38:0::1;131132:17:::2;:15;:17::i;:::-;131160:22;:20;:22::i;:::-;131227:11;:26:::0;;-1:-1:-1;;;;;;131227:26:0::2;-1:-1:-1::0;;;;;131227:26:0;::::2;::::0;;::::2;::::0;;;131280:20:::2;::::0;;-1:-1:-1;;;131280:20:0;;;;:18:::2;::::0;:20:::2;::::0;;::::2;::::0;::::2;::::0;;;;;;;;;131227:26;131280:20;::::2;;::::0;::::2;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131264:6;;:37;;;;;-1:-1:-1::0;;;;;131264:37:0::2;;;;;-1:-1:-1::0;;;;;131264:37:0::2;;;;;;131342:12;-1:-1:-1::0;;;;;131342:25:0::2;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131312:13;:58:::0;;-1:-1:-1;;;;;;131312:58:0;;::::2;-1:-1:-1::0;;;;;131312:58:0;;::::2;;::::0;;;131381:11:::2;:26:::0;;;;::::2;::::0;;::::2;;::::0;;131460:6:::2;::::0;131437:42:::2;::::0;;-1:-1:-1;;;131437:42:0;;;;131460:6;;;::::2;::::0;131437:40:::2;::::0;:42:::2;::::0;;::::2;::::0;::::2;::::0;;;;;;;;131460:6;131437:42;::::2;;::::0;::::2;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131432:48;::::0;:2:::2;:48;:::i;:::-;131418:11;:62:::0;131995:11:::2;::::0;131958:50:::2;::::0;-1:-1:-1;;;;;;;;;;;112907:29:0;-1:-1:-1;;;;;131995:11:0::2;131958:10;:50::i;:::-;132121:46;-1:-1:-1::0;;;;;;;;;;;;;;;;;;;;;;132121:13:0::2;:46::i;:::-;132178:49;-1:-1:-1::0;;;;;;;;;;;112907:29:0;132178:13:::2;:49::i;:::-;132379:8;:6;:8::i;:::-;1846:1:::1;1864:14:::0;1860:68;;;1895:13;:21;;-1:-1:-1;;1895:21:0;;;1573:362;130932:1463;;:::o;83226:31::-;;;;;;;;;;;;152448:198;152508:7;152601:26;;;:13;:26;;;;;:36;;152556:42;;;;;152535:103;;152543:11;;152556:81;;152601:36;152556:81;:::i;:::-;152535:7;:103::i;124805:578::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;124981:14:::1;72459:5;76078:4;-1:-1:-1::0;;;;;76078:19:0::1;;;76070:33;;;::::0;-1:-1:-1;;;76070:33:0;;25353:2:1;76070:33:0::1;::::0;::::1;25335:21:1::0;25392:1;25372:18;;;25365:29;-1:-1:-1;;;25410:18:1;;;25403:31;25451:18;;76070:33:0::1;25151:324:1::0;76070:33:0::1;125025:13:::2;72459:5;76078:4;-1:-1:-1::0;;;;;76078:19:0::2;;;76070:33;;;::::0;-1:-1:-1;;;76070:33:0;;25353:2:1;76070:33:0::2;::::0;::::2;25335:21:1::0;25392:1;25372:18;;;25365:29;-1:-1:-1;;;25410:18:1;;;25403:31;25451:18;;76070:33:0::2;25151:324:1::0;76070:33:0::2;125082:13:::3;-1:-1:-1::0;;;;;125064:31:0::3;:14;-1:-1:-1::0;;;;;125064:31:0::3;;;125056:45;;;::::0;-1:-1:-1;;;125056:45:0;;34213:2:1;125056:45:0::3;::::0;::::3;34195:21:1::0;34252:1;34232:18;;;34225:29;-1:-1:-1;;;34270:18:1;;;34263:31;34311:18;;125056:45:0::3;34011:324:1::0;125056:45:0::3;125112:12;:28:::0;;125151:30;;-1:-1:-1;;;;;;;;125112:28:0;;::::3;::::0;;;::::3;-1:-1:-1::0;;;;125151:30:0;;;;;-1:-1:-1;;;125151:30:0;;::::3;::::0;;::::3;;::::0;;;125254:13:::3;::::0;:46:::3;::::0;-1:-1:-1;;;125254:46:0;;::::3;::::0;::::3;36277:50:1::0;;;;-1:-1:-1;;;;;125254:13:0::3;::::0;:30:::3;::::0;36250:18:1;;125254:46:0::3;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;::::0;::::3;;;;;-1:-1:-1::0;;125316:59:0::3;::::0;;-1:-1:-1;;;;;36563:15:1;;;36545:34;;36615:15;;36610:2;36595:18;;36588:43;125316:59:0::3;::::0;-1:-1:-1;36481:18:1;;-1:-1:-1;125316:59:0::3;36338:299:1::0;121142:154:0;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;121230:18;;::::1;::::0;:7:::1;::::0;:18:::1;::::0;::::1;::::0;::::1;:::i;:::-;;121264:24;121279:8;121264:24;;;;;;:::i;154907:126::-:0;154977:7;155004:21;155013:11;155004:8;:21::i;88170:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;140841:1853::-;4439:7;;;;4693:9;4685:38;;;;-1:-1:-1;;;4685:38:0;;;;;;;:::i;:::-;141005:10:::1;141017:11;113502:39;113521:6;113529:11;113502:18;:39::i;:::-;113494:54;;;;-1:-1:-1::0;;;113494:54:0::1;;;;;;;:::i;:::-;141105:26:::2;141134::::0;;;:13:::2;:26;::::0;;;;;;;141105:55;;::::2;::::0;::::2;::::0;;;;;;::::2;::::0;::::2;::::0;;;::::2;::::0;;;;::::2;::::0;::::2;::::0;;;;;;;;::::2;;::::0;;;;;;141194:17:::2;:15;:17::i;:::-;141171:40;;;141225:21;141248:18:::0;141270:51:::2;141288:11;141301:9;141312:8;141270:17;:51::i;:::-;141224:97;;;;141336:10;141350:1;141336:15;141332:1355;;;141563:8;::::0;141536:24:::2;::::0;::::2;::::0;141575:15:::2;::::0;141536:35:::2;::::0;-1:-1:-1;;;141563:8:0;;::::2;-1:-1:-1::0;;;;;141563:8:0::2;::::0;141536:35:::2;:::i;:::-;:54;;141535:231;;;;;141752:13;141743:6;:22;141535:231;:283;;;;;141801:9;:16;;;141792:6;:25;141535:283;:815;;;;-1:-1:-1::0;142339:11:0::2;::::0;-1:-1:-1;;;142339:11:0;::::2;-1:-1:-1::0;;;;;142339:11:0::2;142313:22;142329:6:::0;142313:13;:22:::2;:::i;:::-;142312:38;;;;:::i;:::-;72459:5;142269:9;:25;;;:39;;;;:::i;:::-;:81;;141535:815;:924;;;;-1:-1:-1::0;142448:11:0::2;::::0;142419:16:::2;::::0;::::2;::::0;-1:-1:-1;;;142448:11:0;;::::2;-1:-1:-1::0;;;;;142448:11:0::2;::::0;142419:25:::2;::::0;142438:6;;142419:25:::2;:::i;:::-;142418:41;;;;:::i;:::-;72459:5;142375:9;:25;;;:39;;;;:::i;:::-;:84;;141535:924;141438:1059;;;::::0;-1:-1:-1;;;141438:1059:0;;34542:2:1;141438:1059:0::2;::::0;::::2;34524:21:1::0;34581:1;34561:18;;;34554:29;-1:-1:-1;;;34599:18:1;;;34592:32;34641:18;;141438:1059:0::2;34340:325:1::0;141438:1059:0::2;142512:26;::::0;;;:13:::2;:26;::::0;;;;:33:::2;;:43:::0;;142549:6;;142512:26;:43:::2;::::0;142549:6;;142512:43:::2;:::i;:::-;;;;;;;;142575:56;142592:11;142624:6;142605:9;:16;;;:25;;;;:::i;:::-;142575:56;::::0;;35658:25:1;;;35714:2;35699:18;;35692:34;;;;35631:18;142575:56:0::2;;;;;;;142648:27;142664:2;142668:6;142648:15;:27::i;:::-;141030:1664;;;;4734:1:::1;;140841:1853:::0;;;:::o;154621:161::-;154687:7;-1:-1:-1;;;;;154715:19:0;;154707:33;;;;-1:-1:-1;;;154707:33:0;;24314:2:1;154707:33:0;;;24296:21:1;24353:1;24333:18;;;24326:29;-1:-1:-1;;;24371:18:1;;;24364:31;24412:18;;154707:33:0;24112:324:1;154707:33:0;-1:-1:-1;;;;;;154758:16:0;;;;;:9;:16;;;;;;;154621:161::o;128819:150::-;128914:13;;-1:-1:-1;;;;;128914:13:0;128892:10;:36;128884:50;;;;-1:-1:-1;;;128884:50:0;;;;;;;:::i;:::-;128945:6;:16;;-1:-1:-1;;;;;;128945:16:0;-1:-1:-1;;;;;128945:16:0;;;;;;;;;;128819:150::o;143469:1159::-;4439:7;;;;4693:9;4685:38;;;;-1:-1:-1;;;4685:38:0;;;;;;;:::i;:::-;143610:16:::1;143632:17;:15;:17::i;:::-;-1:-1:-1::0;143609:40:0;-1:-1:-1;143660:23:0::1;::::0;143694:810:::1;143718:12;:19;143714:1;:23;143694:810;;;143759:19;143781:12;143794:1;143781:15;;;;;;;;:::i;:::-;;;;;;;143759:37;;143815:20;143823:11;107732:4:::0;107756:20;;;:7;:20;;;;;;-1:-1:-1;;;;;107756:20:0;:34;;;107671:127;143815:20:::1;143811:682;;;143899:26;143928::::0;;;:13:::1;:26;::::0;;;;;;;143899:55;;::::1;::::0;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;;;;;::::1;;::::0;;;;;;:26;144019:51:::1;143942:11:::0;143899:55;144061:8;144019:17:::1;:51::i;:::-;143973:97;;;;144093:10;144107:1;144093:15;144089:389;;;144414:44;144444:13;144414:29;:44::i;:::-;144395:63;::::0;;::::1;:::i;:::-;;;144089:389;143837:656;;;143811:682;-1:-1:-1::0;143739:3:0;::::1;::::0;::::1;:::i;:::-;;;;143694:810;;;-1:-1:-1::0;144519:46:0::1;::::0;;144537:10:::1;20115:74:1::0;;20220:2;20205:18;;20198:34;;;144519:46:0::1;::::0;20088:18:1;144519:46:0::1;;;;;;;144576:44;144592:10;144604:15;144576;:44::i;123777:494::-:0;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;123965:8:::1;123975;75480:6;:13;75463:6;:13;:30;:51;;;;;75513:1;75497:6;:13;:17;75463:51;75455:65;;;::::0;-1:-1:-1;;;75455:65:0;;32814:2:1;75455:65:0::1;::::0;::::1;32796:21:1::0;32853:1;32833:18;;;32826:29;-1:-1:-1;;;32871:18:1;;;32864:31;32912:18;;75455:65:0::1;32612:324:1::0;75455:65:0::1;75536:9;75531:257;75572:1;75556:6;:13;:17;;;;:::i;:::-;75551:1;:22;75531:257;;72459:5;-1:-1:-1::0;;;;;75603:32:0::1;:6;75610:1;75603:9;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;75603:32:0::1;;;:68;;;;;72459:5;-1:-1:-1::0;;;;;75639:32:0::1;:6;75646:1;75639:9;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;75639:32:0::1;;;75603:68;75595:82;;;::::0;-1:-1:-1;;;75595:82:0;;33884:2:1;75595:82:0::1;::::0;::::1;33866:21:1::0;33923:1;33903:18;;;33896:29;-1:-1:-1;;;33941:18:1;;;33934:31;33982:18;;75595:82:0::1;33682:324:1::0;75595:82:0::1;75696:5:::0;;75692:85:::1;;75742:6:::0;75749:5:::1;75753:1;75749::::0;:5:::1;:::i;:::-;75742:13;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;75730:25:0::1;:6;75737:1;75730:9;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;75730:25:0::1;;75722:39;;;::::0;-1:-1:-1;;;75722:39:0;;26342:2:1;75722:39:0::1;::::0;::::1;26324:21:1::0;26381:1;26361:18;;;26354:29;-1:-1:-1;;;26399:18:1;;;26392:31;26440:18;;75722:39:0::1;26140:324:1::0;75722:39:0::1;75575:3:::0;::::1;::::0;::::1;:::i;:::-;;;;75531:257;;;;124000:7:::2;:12;;124011:1;124000:12;123996:210;;;124029:25:::0;;::::2;::::0;:14:::2;::::0;:25:::2;::::0;::::2;::::0;::::2;:::i;:::-;-1:-1:-1::0;124069:25:0;;::::2;::::0;:14:::2;::::0;:25:::2;::::0;::::2;::::0;::::2;:::i;:::-;;123996:210;;;124127:26:::0;;::::2;::::0;:15:::2;::::0;:26:::2;::::0;::::2;::::0;::::2;:::i;:::-;-1:-1:-1::0;124168:26:0;;::::2;::::0;:15:::2;::::0;:26:::2;::::0;::::2;::::0;::::2;:::i;:::-;;123996:210;124221:42;124235:8;124245;124255:7;124221:42;;;;;;;;:::i;:::-;;;;;;;;44361:1:::1;;123777:494:::0;;;;:::o;119548:86::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;119618:8:::1;:6;:8::i;118173:232::-:0;113726:19;;-1:-1:-1;;;;;113726:19:0;113712:10;:33;113704:47;;;;-1:-1:-1;;;113704:47:0;;;;;;;:::i;:::-;118291:19:::1;:42:::0;;-1:-1:-1;;;;;;118291:42:0::1;-1:-1:-1::0;;;;;118291:42:0;::::1;::::0;;::::1;::::0;;;118349:48:::1;::::0;::::1;::::0;-1:-1:-1;;118349:48:0::1;118173:232:::0;:::o;156350:260::-;-1:-1:-1;;;;;156447:22:0;;156459:10;156447:22;;156439:37;;;;-1:-1:-1;;;156439:37:0;;26012:2:1;156439:37:0;;;25994:21:1;26051:1;26031:18;;;26024:29;-1:-1:-1;;;26069:18:1;;;26062:32;26111:18;;156439:37:0;25810:325:1;156439:37:0;156506:10;156487:30;;;;:18;:30;;;;;;;-1:-1:-1;;;;;156487:40:0;;;;;;;;;;:51;;-1:-1:-1;;156487:51:0;;;;;;;:40;-1:-1:-1;;;;;156554:48:0;;156593:8;156554:48;;;;22924:14:1;22917:22;22899:41;;22887:2;22872:18;;22759:187;156554:48:0;;;;;;;;156350:260;;:::o;133487:2628::-;133721:19;4694:8;4439:7;;;;;4368:86;4694:8;4693:9;4685:38;;;;-1:-1:-1;;;4685:38:0;;;;;;;:::i;:::-;133705:5;-1:-1:-1;;;;;76413:24:0;::::1;76405:38;;;::::0;-1:-1:-1;;;76405:38:0;;24314:2:1;76405:38:0::1;::::0;::::1;24296:21:1::0;24353:1;24333:18;;;24326:29;-1:-1:-1;;;24371:18:1;;;24364:31;24412:18;;76405:38:0::1;24112:324:1::0;76405:38:0::1;133842:1:::2;133824:15;:19;133816:34;;;::::0;-1:-1:-1;;;133816:34:0;;27078:2:1;133816:34:0::2;::::0;::::2;27060:21:1::0;27117:1;27097:18;;;27090:29;-1:-1:-1;;;27135:18:1;;;27128:32;27177:18;;133816:34:0::2;26876:325:1::0;133816:34:0::2;134163:11;::::0;134119:6:::2;::::0;:65:::2;::::0;-1:-1:-1;;;;;134119:6:0;;::::2;::::0;134143:10:::2;::::0;134163:11:::2;134177:6:::0;134119:23:::2;:65::i;:::-;134347:14;134365:17;:15;:17::i;:::-;134344:38;;;134599:13;134589:6;:23;;134581:38;;;::::0;-1:-1:-1;;;134581:38:0;;30808:2:1;134581:38:0::2;::::0;::::2;30790:21:1::0;30847:1;30827:18;;;30820:29;-1:-1:-1;;;30865:18:1;;;30858:32;30907:18;;134581:38:0::2;30606:325:1::0;134581:38:0::2;134741:30;134803:11:::0;;134775:24:::2;134793:6:::0;134775:15;:24:::2;:::i;:::-;134774:40;;;;:::i;:::-;134741:73;;134907:17;134927:62;134941:6;134949:22;134973:15;134927:13;:62::i;:::-;134907:82;;135021:12;135008:9;:25;;135000:40;;;::::0;-1:-1:-1;;;135000:40:0;;28743:2:1;135000:40:0::2;::::0;::::2;28725:21:1::0;28782:1;28762:18;;;28755:29;-1:-1:-1;;;28800:18:1;;;28793:32;28842:18;;135000:40:0::2;28541:325:1::0;135000:40:0::2;135184:11;::::0;:23:::2;::::0;135198:9;;-1:-1:-1;;;135184:11:0;::::2;-1:-1:-1::0;;;;;135184:11:0::2;:23;:::i;:::-;135150:29;72459:5;135150:15:::0;:29:::2;:::i;:::-;135149:58;;135141:73;;;::::0;-1:-1:-1;;;135141:73:0;;31797:2:1;135141:73:0::2;::::0;::::2;31779:21:1::0;31836:1;31816:18;;;31809:29;-1:-1:-1;;;31854:18:1;;;31847:32;31896:18;;135141:73:0::2;31595:325:1::0;135141:73:0::2;135252:29;:17;21806:19:::0;;21824:1;21806:19;;;21717:127;135252:29:::2;135306:17;21687:14:::0;135292:41:::2;;135476:29;135490:11;135503:1;135476:13;:29::i;:::-;135632:22;135612:16;;:42;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;135696:62:0::2;::::0;;::::2;::::0;::::2;::::0;;;;;135714:15:::2;135696:62;::::0;;::::2;::::0;;;;;;;;;;;;;;;-1:-1:-1;135667:26:0;;;:13:::2;:26:::0;;;;;;;:91;;;;;;::::2;::::0;::::2;::::0;;::::2;::::0;::::2;::::0;;;::::2;::::0;;::::2;::::0;136002:25:::2;136008:5:::0;135681:11;136002:5:::2;:25::i;:::-;136043:64;::::0;;35968:25:1;;;36024:2;36009:18;;36002:34;;;36052:18;;;36045:34;;;36110:2;36095:18;;36088:34;;;136043:64:0::2;::::0;35955:3:1;35940:19;136043:64:0::2;;;;;;;133742:2373;;;4734:1:::1;133487:2628:::0;;;;;;;:::o;114512:575::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;114733:9:::1;114728:119;114752:12;:19;114748:1;:23;114728:119;;;114793:42;-1:-1:-1::0;;;;;;;;;;;114819:12:0::1;114832:1;114819:15;;;;;;;;:::i;:::-;;;;;;;114793:10;:42::i;:::-;114773:3:::0;::::1;::::0;::::1;:::i;:::-;;;;114728:119;;;;114921:35;-1:-1:-1::0;;;;;;;;;;;114947:8:0::1;114921:10;:35::i;:::-;115001:13;::::0;114967:49:::1;::::0;-1:-1:-1;;;;;;;;;;;112786:26:0;-1:-1:-1;;;;;115001:13:0::1;114967:10;:49::i;:::-;-1:-1:-1::0;115027:11:0::1;:25:::0;;-1:-1:-1;;;;;115027:25:0;;::::1;-1:-1:-1::0;;;;;;115027:25:0;;::::1;;::::0;;;115063:6:::1;:16:::0;;;;;::::1;::::0;::::1;;::::0;;-1:-1:-1;;114512:575:0:o;125633:358::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;125805:27:::1;72459:5;76078:4;-1:-1:-1::0;;;;;76078:19:0::1;;;76070:33;;;::::0;-1:-1:-1;;;76070:33:0;;25353:2:1;76070:33:0::1;::::0;::::1;25335:21:1::0;25392:1;25372:18;;;25365:29;-1:-1:-1;;;25410:18:1;;;25403:31;25451:18;;76070:33:0::1;25151:324:1::0;76070:33:0::1;125850:26:::2;:56:::0;;-1:-1:-1;;;;;125850:56:0::2;-1:-1:-1::0;;;;;;;;125850:56:0;;::::2;::::0;::::2;::::0;;;::::2;::::0;;;;125922:61:::2;::::0;125956:26;::::2;;36277:50:1::0;;125922:61:0::2;::::0;36265:2:1;36250:18;125922:61:0::2;36133:200:1::0;158374:259:0;158546:10;158558:11;113502:39;113521:6;113529:11;113502:18;:39::i;:::-;113494:54;;;;-1:-1:-1;;;113494:54:0;;;;;;;:::i;:::-;158582:43:::1;158596:4;158602:2;158606:11;158619:5;158582:13;:43::i;:::-;158374:259:::0;;;;;;:::o;145393:6026::-;4439:7;;;;4693:9;4685:38;;;;-1:-1:-1;;;4685:38:0;;;;;;;:::i;:::-;145624:16:::1;145642:14:::0;145660:17:::1;:15;:17::i;:::-;145623:54;;;;145774:19;145796:13;;;;;;;;;-1:-1:-1::0;;;;;145796:13:0::1;-1:-1:-1::0;;;;;145796:28:0::1;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;145880:13;::::0;145774:52;;-1:-1:-1;145837:25:0::1;::::0;72459:5:::1;::::0;145866:27:::1;::::0;-1:-1:-1;;;145880:13:0;::::1;-1:-1:-1::0;;;;;145880:13:0::1;145774:52:::0;145866:27:::1;:::i;:::-;145865:43;;;;:::i;:::-;146040:12;::::0;145837:71;;-1:-1:-1;72459:5:0::1;::::0;146026:26:::1;::::0;-1:-1:-1;;;146040:12:0;::::1;-1:-1:-1::0;;;;;146040:12:0::1;146026:11:::0;:26:::1;:::i;:::-;146025:42;;;;:::i;:::-;146006:16;;:61;145998:76;;;::::0;-1:-1:-1;;;145998:76:0;;29073:2:1;145998:76:0::1;::::0;::::1;29055:21:1::0;29112:1;29092:18;;;29085:29;-1:-1:-1;;;29130:18:1;;;29123:32;29172:18;;145998:76:0::1;28871:325:1::0;145998:76:0::1;146085:23;146119:19:::0;146206:26:::1;146247:12;:19;-1:-1:-1::0;;;;;146235:32:0::1;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;;;;;;;;;;;;;146235:32:0::1;;;;;;;;;;;;;;;;146206:61;;146285:9;146280:2801;146304:12;:19;146300:1;:23;146280:2801;;;146345:19;146367:12;146380:1;146367:15;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;;;146397:13:::1;146413:20:::0;;;:7:::1;:20:::0;;;;;;;;146367:15;;-1:-1:-1;;;;;;146413:20:0::1;146452:19:::0;;146448:2622:::1;;146564:26;146593::::0;;;:13:::1;:26;::::0;;;;;;;146564:55;;::::1;::::0;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;;;;;::::1;;::::0;;;;;;:26;146761:51:::1;146607:11:::0;146564:55;146803:8;146761:17:::1;:51::i;:::-;146715:97;;;;146835:10;146849:1;146835:15;146831:2070;;;147325:44;147355:13;147325:29;:44::i;:::-;147306:63;::::0;;::::1;:::i;:::-;;;146831:2070;;;147426:8;::::0;147399:24:::1;::::0;::::1;::::0;147438:15:::1;::::0;147399:35:::1;::::0;-1:-1:-1;;;147426:8:0;;::::1;-1:-1:-1::0;;;;;147426:8:0::1;::::0;147399:35:::1;:::i;:::-;:54;147395:1506;;147810:39;147826:11;147839:9;147810:15;:39::i;:::-;147872:23;148032:16;;148012:17;:36;148008:267;;;148138:17;72459:5;148104:16;;:30;;;;:::i;:::-;148103:52;;;;:::i;:::-;148077:79;;148008:267;;;-1:-1:-1::0;72459:5:0::1;148008:267;148396:24;148422:12:::0;148438:178:::1;148485:13;148525:9;:25;;;148577:16;148438:20;:178::i;:::-;148395:221:::0;;-1:-1:-1;148395:221:0;-1:-1:-1;148639:19:0::1;148395:221:::0;148639:19;::::1;:::i;:::-;;;148851:30;;;;;;;;148857:5;-1:-1:-1::0;;;;;148851:30:0::1;;;;;148864:16;148851:30;;::::0;148834:11:::1;148846:1;148834:14;;;;;;;;:::i;:::-;;;;;;:47;;;;147455:1446;;;147395:1506;149030:17;149010:16;;:37;149006:48;;149049:5;;;;;;;149006:48;146473:2597;;;146448:2622;146330:2751;;146325:3;;;;;:::i;:::-;;;;146280:2801;;;-1:-1:-1::0;149093:12:0::1;149109:22:::0;;149108:123:::1;;149208:21;149212:17:::0;149208:1:::1;:21;:::i;:::-;72459:5;149173:16;;:30;;;;:::i;:::-;149172:58;;;;:::i;:::-;149108:123;;;149148:1;149108:123;149093:138;;72459:5;149755:63;149772:5;149779:18;149755:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;149755:63:0::1;-1:-1:-1::0;;;;;149755:63:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149799:18;149755:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;149755:63:0::1;-1:-1:-1::0;;;;;149755:63:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:63::i;:::-;149741:77;::::0;-1:-1:-1;;;;;149741:77:0::1;:11:::0;:77:::1;:::i;:::-;149740:93;;;;:::i;:::-;149726:107;;149969:20;;149955:11;:34;:71;;150006:20;;149955:71;;;149992:11;149955:71;149941:85:::0;-1:-1:-1;150707:21:0::1;72459:5;150812:14;:6:::0;150821:5:::1;150812:14;:::i;:::-;:28;;;;:::i;:::-;150783:11;::::0;150752:13:::1;::::0;150769:11;;150737:28:::1;::::0;-1:-1:-1;;;;;;;;150752:13:0;::::1;::::0;::::1;::::0;-1:-1:-1;;;150737:12:0;::::1;;:28;:::i;:::-;150732:34;::::0;:1:::1;:34;:::i;:::-;-1:-1:-1::0;;;;;150732:48:0::1;;;;;:::i;:::-;:62;;;;:::i;:::-;150731:110;;;;:::i;:::-;150707:134;;150880:13;150866:11;:27;:57;;150910:13;150866:57;;;150896:11;150866:57;150852:71:::0;-1:-1:-1;150941:91:0::1;150963:12:::0;150977:11;150990:10:::1;151002:29;151016:15:::0;150852:71;151002:29:::1;:::i;:::-;150941:91;;;;;;;;;:::i;:::-;;;;;;;;151126:9;151121:222;151145:12;:19;151141:1;:23;151121:222;;;151224:1;151190:11;151202:1;151190:14;;;;;;;;:::i;:::-;;;;;;;:31;;;:35;151186:146;;;151246:70;151262:11;151274:1;151262:14;;;;;;;;:::i;:::-;;;;;;;:20;;;151284:11;151296:1;151284:14;;;;;;;;:::i;:::-;;;;;;;:31;;;151246:15;:70::i;:::-;151166:3:::0;::::1;::::0;::::1;:::i;:::-;;;;151121:222;;;-1:-1:-1::0;151353:58:0::1;151369:10;151381:29;151395:15:::0;151381:11;:29:::1;:::i;:::-;151353:15;:58::i;:::-;145486:5933;;;;;;;;;145393:6026:::0;:::o;82847:30::-;;;;;;;;;;;;118949:234;119069:11;;-1:-1:-1;;;;;119069:11:0;119047:10;:34;119039:48;;;;-1:-1:-1;;;119039:48:0;;;;;;;:::i;:::-;119098:19;:32;;-1:-1:-1;;;;;119141:34:0;;;-1:-1:-1;;;119141:34:0;-1:-1:-1;;;;;;119141:34:0;;;119098:32;;;;119141:34;;;;;;;;;;118949:234::o;153695:752::-;107732:4;107756:20;;;:7;:20;;;;;;153766:13;;-1:-1:-1;;;;;107756:20:0;153792:34;;;;-1:-1:-1;;;153792:34:0;;31468:2:1;153792:34:0;;;31450:21:1;31507:1;31487:18;;;31480:29;-1:-1:-1;;;31525:18:1;;;31518:31;31566:18;;153792:34:0;31266:324:1;153792:34:0;153983:11;153968:12;154030:78;154037:9;;154030:78;;154063:8;;;;:::i;:::-;;-1:-1:-1;154086:10:0;;-1:-1:-1;154094:2:0;154086:10;;:::i;:::-;;;154030:78;;;154118:19;154150:6;-1:-1:-1;;;;;154140:17:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;154140:17:0;;154118:39;;154168:172;154175:16;;154168:172;;154208:11;154218:1;154208:11;;:::i;:::-;;-1:-1:-1;154277:16:0;154291:2;154277:11;:16;:::i;:::-;154264:30;;:2;:30;:::i;:::-;154251:45;;154234:6;154241;154234:14;;;;;;;;:::i;:::-;;;;:62;-1:-1:-1;;;;;154234:62:0;;;;;;;;-1:-1:-1;154311:17:0;154326:2;154311:17;;:::i;:::-;;;154168:172;;;154381:1;154363:7;154357:21;;;;;:::i;:::-;;;:25;:82;;;;;;;;;;;;;;;;;154409:7;154425:6;154392:41;;;;;;;;;:::i;:::-;;;;;;;;;;;;;154357:82;154350:89;153695:752;-1:-1:-1;;;;;153695:752:0:o;87491:34::-;;;;;;;;;;;;46370:143;45665:7;45692:12;;;:6;:12;;;;;:22;;;44322:28;44333:4;44339:10;44322;:28::i;:::-;46479:26:::1;46491:4;46497:7;46479:11;:26::i;83317:31::-:0;;;;;;;;;;;;151975:237;152068:7;152126:26;;;:13;:26;;;;;;;;152097:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;152068:7;;152170:34;152097:55;152199:4;152170:17;:34::i;:::-;152163:41;;;;;151975:237;;;;;:::o;120545:378::-;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;120702:20;-1:-1:-1;;;;;76413:24:0;::::1;76405:38;;;::::0;-1:-1:-1;;;76405:38:0;;24314:2:1;76405:38:0::1;::::0;::::1;24296:21:1::0;24353:1;24333:18;;;24326:29;-1:-1:-1;;;24371:18:1;;;24364:31;24412:18;;76405:38:0::1;24112:324:1::0;76405:38:0::1;120740:15:::2;:34:::0;;;120785:19:::2;:42:::0;;-1:-1:-1;;;;;;120785:42:0::2;-1:-1:-1::0;;;;;120785:42:0;::::2;::::0;;::::2;::::0;;;120843:72:::2;::::0;23097:25:1;;;120843:72:0::2;::::0;23085:2:1;23070:18;120843:72:0::2;;;;;;;;44361:1:::1;120545:378:::0;;;:::o;137188:1759::-;4439:7;;;;4693:9;4685:38;;;;-1:-1:-1;;;4685:38:0;;;;;;;:::i;:::-;137357:10:::1;137369:11;113502:39;113521:6;113529:11;113502:18;:39::i;:::-;113494:54;;;;-1:-1:-1::0;;;113494:54:0::1;;;;;;;:::i;:::-;137457:26:::2;137486::::0;;;:13:::2;:26;::::0;;;;;;;137457:55;;::::2;::::0;::::2;::::0;;;;;;::::2;::::0;::::2;::::0;;;::::2;::::0;;;;::::2;::::0;::::2;::::0;;;;;;;;::::2;;::::0;;;;;;137546:17:::2;:15;:17::i;:::-;137523:40;;;137781:21;137804:18:::0;137826:51:::2;137844:11;137857:9;137868:8;137826:17;:51::i;:::-;137780:97;;;;137892:10;137906:1;137892:15;137888:1052;;;138065:8;::::0;138038:24:::2;::::0;::::2;::::0;138077:15:::2;::::0;138038:35:::2;::::0;-1:-1:-1;;;138065:8:0;;::::2;-1:-1:-1::0;;;;;138065:8:0::2;::::0;138038:35:::2;:::i;:::-;:54;;138030:69;;;::::0;-1:-1:-1;;;138030:69:0;;30478:2:1;138030:69:0::2;::::0;::::2;30460:21:1::0;30517:1;30497:18;;;30490:29;-1:-1:-1;;;30535:18:1;;;30528:32;30577:18;;138030:69:0::2;30276:325:1::0;138030:69:0::2;138167:39;138183:11;138196:9;138167:15;:39::i;:::-;138340:24;138370:374;138409:13;138441:9;:25;;;138693:36;138712:16;;138693:18;:36::i;:::-;138370:20;:374::i;:::-;138339:405;;;138787:16;138767;:36;;138759:51;;;::::0;-1:-1:-1;;;138759:51:0;;30148:2:1;138759:51:0::2;::::0;::::2;30130:21:1::0;30187:1;30167:18;;;30160:29;-1:-1:-1;;;30205:18:1;;;30198:32;30247:18;;138759:51:0::2;29946:325:1::0;138759:51:0::2;138830:46;::::0;;35658:25:1;;;35714:2;35699:18;;35692:34;;;138830:46:0::2;::::0;35631:18:1;138830:46:0::2;;;;;;;138891:37;138907:2;138911:16;138891:15;:37::i;122339:496::-:0;-1:-1:-1;;;;;;;;;;;44322:28:0;44333:4;44339:10;44322;:28::i;:::-;122512:18:::1;72459:5;76078:4;-1:-1:-1::0;;;;;76078:19:0::1;;;76070:33;;;::::0;-1:-1:-1;;;76070:33:0;;25353:2:1;76070:33:0::1;::::0;::::1;25335:21:1::0;25392:1;25372:18;;;25365:29;-1:-1:-1;;;25410:18:1;;;25403:31;25451:18;;76070:33:0::1;25151:324:1::0;76070:33:0::1;122630::::2;122645:18:::0;122630:12;:33:::2;:::i;:::-;-1:-1:-1::0;;;;;122613:50:0::2;:14;122626:1;72459:5;122613:14;:::i;:::-;:50;122605:64;;;::::0;-1:-1:-1;;;122605:64:0;;34213:2:1;122605:64:0::2;::::0;::::2;34195:21:1::0;34252:1;34232:18;;;34225:29;-1:-1:-1;;;34270:18:1;;;34263:31;34311:18;;122605:64:0::2;34011:324:1::0;122605:64:0::2;122680:11;:26:::0;;-1:-1:-1;;;;;;122717:38:0;-1:-1:-1;;;;;;;;122680:26:0;;::::2;::::0;;::::2;-1:-1:-1::0;;122717:38:0;;;;;;;::::2;::::0;;::::2;::::0;;;122771:56:::2;::::0;;36545:34:1;;;36610:2;36595:18;;36588:43;;;;122771:56:0::2;::::0;36481:18:1;122771:56:0::2;;;;;;;44361:1:::1;122339:496:::0;;;:::o;105728:168::-;105790:13;105824:20;;;:7;:20;;;;;;-1:-1:-1;;;;;105824:20:0;105863:19;105855:33;;;;-1:-1:-1;;;105855:33:0;;31468:2:1;105855:33:0;;;31450:21:1;31507:1;31487:18;;;31480:29;-1:-1:-1;;;31525:18:1;;;31518:31;31566:18;;105855:33:0;31266:324:1;105855:33:0;105728:168;;;:::o;110235:180::-;110306:32;;;;:19;:32;;;;;:37;;-1:-1:-1;;;;;;110306:37:0;-1:-1:-1;;;;;110306:37:0;;;;;;;;:32;;110368:21;110306:32;110368:8;:21::i;:::-;-1:-1:-1;;;;;110359:48:0;;;;;;;;;;;110235:180;;:::o;34436:211::-;34580:58;;-1:-1:-1;;;;;20133:55:1;;34580:58:0;;;20115:74:1;20205:18;;;20198:34;;;34553:86:0;;34573:5;;-1:-1:-1;;;34603:23:0;20088:18:1;;34580:58:0;;;;-1:-1:-1;;34580:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;34580:58:0;-1:-1:-1;;;;;;34580:58:0;;;;;;;;;;34553:19;:86::i;107923:322::-;108012:4;108086:13;108102:21;108111:11;108102:8;:21::i;:::-;108086:37;;108153:5;-1:-1:-1;;;;;108142:16:0;:7;-1:-1:-1;;;;;108142:16:0;;:56;;;-1:-1:-1;106142:7:0;106169:32;;;:19;:32;;;;;;-1:-1:-1;;;;;108162:36:0;;;106169:32;;108162:36;108142:56;:94;;;-1:-1:-1;;;;;;108202:25:0;;;;;;;:18;:25;;;;;;;:34;;;;;;;;;;;;108142:94;108134:103;107923:322;-1:-1:-1;;;;107923:322:0:o;102714:1018::-;102790:33;102804:11;102817:5;102790:13;:33::i;:::-;102834:14;102851:20;;;:7;:20;;;;;;102886:10;;102882:843;;102936:1;102913:20;;;:7;:20;;;;;;;;:24;;;102968:7;:20;;;;;;103629:11;;-1:-1:-1;;;;;102968:20:0;;;;103629:39;;:11;102968:20;103661:6;103629:24;:39::i;:::-;103699:5;-1:-1:-1;;;;;103688:25:0;;103706:6;103688:25;;;;23097::1;;23085:2;23070:18;;22951:177;109710:458:0;109863:4;-1:-1:-1;;;;;109838:29:0;:21;109847:11;109838:8;:21::i;:::-;-1:-1:-1;;;;;109838:29:0;;109830:43;;;;-1:-1:-1;;;109830:43:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;109892:16:0;;109884:31;;;;-1:-1:-1;;;109884:31:0;;31138:2:1;109884:31:0;;;31120:21:1;31177:1;31157:18;;;31150:29;-1:-1:-1;;;31195:18:1;;;31188:32;31237:18;;109884:31:0;30936:325:1;109884:31:0;109980:33;109997:1;110001:11;109980:8;:33::i;:::-;-1:-1:-1;;;;;110026:15:0;;;;;;:9;:15;;;;;:20;;110045:1;;110026:15;:20;;110045:1;;110026:20;:::i;:::-;;;;-1:-1:-1;;;;;;;110057:13:0;;;;;;:9;:13;;;;;:18;;110074:1;;110057:13;:18;;110074:1;;110057:18;:::i;:::-;;;;-1:-1:-1;;110086:20:0;;;;:7;:20;;;;;;:25;;-1:-1:-1;;;;;;110086:25:0;-1:-1:-1;;;;;110086:25:0;;;;;;;;;110129:31;;110086:20;;110129:31;;;;;;;109710:458;;;:::o;95497:110::-;95583:6;;:16;;;-1:-1:-1;;;95583:16:0;;;;95547:7;;;;-1:-1:-1;;;;;95583:6:0;;;;:14;;:16;;;;;;;;;;;:6;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95576:23;;;;95497:110;;:::o;92670:593::-;92816:7;92825;92845:18;92875:21;92898:30;92932:38;92950:9;92961:8;92932:17;:38::i;:::-;92874:96;;;;92985:13;93002:1;92985:18;:49;;;;93007:22;93033:1;93007:27;92985:49;92981:230;;;93051:39;93067:11;93080:9;93051:15;:39::i;:::-;93198:1;93185:14;;92981:230;-1:-1:-1;93229:13:0;-1:-1:-1;93244:10:0;-1:-1:-1;92670:593:0;;;;;;;:::o;34655:248::-;34826:68;;-1:-1:-1;;;;;19292:15:1;;;34826:68:0;;;19274:34:1;19344:15;;19324:18;;;19317:43;19376:18;;;19369:34;;;34799:96:0;;34819:5;;-1:-1:-1;;;34849:27:0;19186:18:1;;34826:68:0;19011:398:1;34799:96:0;34655:248;;;;:::o;44891:519::-;44540:4;44564:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;44564:29:0;;;;;;;;;;;;44967:436;;45160:52;45199:7;-1:-1:-1;;;;;45160:52:0;45209:2;45160:30;:52::i;:::-;45285:49;45324:4;45331:2;45285:30;:49::i;:::-;45065:292;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;45065:292:0;;;;;;;;;;-1:-1:-1;;;45011:380:0;;;;;;;:::i;48199:228::-;44540:4;44564:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;44564:29:0;;;;;;;;;;;;48270:150;;48314:12;;;;:6;:12;;;;;;;;-1:-1:-1;;;;;48314:29:0;;;;;;;;;;:36;;-1:-1:-1;;48314:36:0;48346:4;48314:36;;;48370:38;48397:10;;48321:4;;48370:38;;48314:12;48370:38;48199:228;;:::o;48435:229::-;44540:4;44564:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;44564:29:0;;;;;;;;;;;;48507:150;;;48582:5;48550:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;48550:29:0;;;;;;;;;;:37;;-1:-1:-1;;48550:37:0;;;48607:38;48634:10;;48557:4;;48607:38;;48582:5;48607:38;48435:229;;:::o;101881:332::-;101931:7;101955:16;;101975:1;101955:21;101951:81;;;-1:-1:-1;102000:20:0;;;101881:332::o;101951:81::-;102189:16;;72255:6;102148:10;;102130:14;;102100:27;:25;:27::i;:::-;:44;;;;:::i;:::-;102099:59;;;;:::i;:::-;:73;;;;:::i;:::-;102098:107;;;;:::i;:::-;102062:20;;:143;;;;:::i;:::-;102042:163;;101881:332;:::o;5427:120::-;4439:7;;;;4963:41;;;;-1:-1:-1;;;4963:41:0;;25004:2:1;4963:41:0;;;24986:21:1;25043:2;25023:18;;;25016:30;-1:-1:-1;;;25062:18:1;;;25055:50;25122:18;;4963:41:0;24802:344:1;4963:41:0;5486:7:::1;:15:::0;;-1:-1:-1;;5486:15:0::1;::::0;;5517:22:::1;2877:10:::0;5526:12:::1;5517:22;::::0;-1:-1:-1;;;;;18944:55:1;;;18926:74;;18914:2;18899:18;5517:22:0::1;;;;;;;5427:120::o:0;4037:131::-;1592:13;;;;;;;;:30;;-1:-1:-1;1610:12:0;;;;1609:13;1592:30;1584:89;;;;-1:-1:-1;;;1584:89:0;;;;;;;:::i;:::-;1709:13;;;;;;;1708:14;1733:101;;;;1768:13;:20;;-1:-1:-1;;1803:19:0;;;;;1733:101;4096:26:::1;:24;:26::i;:::-;4133:27;:25;:27::i;:::-;1864:14:::0;1860:68;;;1895:13;:21;;-1:-1:-1;;1895:21:0;;;1573:362;4037:131::o;42378:104::-;1592:13;;;;;;;;:30;;-1:-1:-1;1610:12:0;;;;1609:13;1592:30;1584:89;;;;-1:-1:-1;;;1584:89:0;;;;;;;:::i;:::-;1709:13;;;;;;;1708:14;1733:101;;;;1768:13;:20;;-1:-1:-1;;1803:19:0;;;;;1733:101;42442:32:::1;:30;:32::i;47768:104::-:0;47839:25;47850:4;47856:7;47839:10;:25::i;48004:187::-;45665:7;45692:12;;;:6;:12;;;;;:22;;;48128:9;;48085:53;;48102:4;;48085:53;;;;;48149:12;;;;:6;:12;;;;;;:22;;:34;48004:187::o;5168:118::-;4439:7;;;;4693:9;4685:38;;;;-1:-1:-1;;;4685:38:0;;;;;;;:::i;:::-;5228:7:::1;:14:::0;;-1:-1:-1;;5228:14:0::1;5238:4;5228:14;::::0;;5258:20:::1;5265:12;2877:10:::0;;2797:98;104384:286;104460:7;104642:20;;;:7;:20;;;;;;;;;104615:11;;104530:27;:40;;;;;;;104642:20;;104615:11;72255:6;;104510:17;:15;:17::i;:::-;:60;;;;:::i;:::-;104501:70;;:5;:70;:::i;:::-;104500:99;;;;:::i;:::-;:126;;;;:::i;:::-;:162;;;;:::i;91208:796::-;91305:11;;:24;;;-1:-1:-1;;;91305:24:0;;;;91284:18;;-1:-1:-1;;;;;91305:11:0;;:22;;:24;;;;;;;;;;;;;;:11;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91284:45;;91358:6;91344:10;:20;;:34;;;;;91377:1;91368:6;:10;91344:34;91340:657;;;91506:11;;91474:6;;:60;;-1:-1:-1;;;;;91474:6:0;;;;91506:11;91520:5;91527:6;91474:23;:60::i;91340:657::-;91556:10;;91552:445;;91806:18;91827:19;91836:10;91827:6;:19;:::i;:::-;91893:11;;91861:6;;91806:40;;-1:-1:-1;91861:64:0;;-1:-1:-1;;;;;91861:6:0;;;;91893:11;91907:5;91914:10;91861:23;:64::i;:::-;91940:13;;:45;;-1:-1:-1;;;91940:45:0;;;;;35356:25:1;;;-1:-1:-1;;;;;35417:55:1;;;35397:18;;;35390:83;91940:13:0;;;;:26;;35329:18:1;;91940:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91568:429;91273:731;91208:796;;:::o;96251:296::-;96397:26;;96336:18;;72459:5;;96381:42;;-1:-1:-1;;;96397:26:0;;-1:-1:-1;;;;;96397:26:0;96381:13;:42;:::i;:::-;96380:58;;;;:::i;:::-;96367:71;;96475:24;;96462:10;:37;:77;;96515:24;;96462:77;;98122:1297;98275:17;98573:12;98588:61;98626:22;98607:16;;:41;;;;:::i;:::-;98588:18;:61::i;:::-;98573:76;-1:-1:-1;72459:5:0;-1:-1:-1;;;;;98668:27:0;;;98660:42;;;;-1:-1:-1;;;98660:42:0;;29818:2:1;98660:42:0;;;29800:21:1;29857:1;29837:18;;;29830:29;-1:-1:-1;;;29875:18:1;;;29868:32;29917:18;;98660:42:0;29616:325:1;98660:42:0;98912:21;72459:5;98959:55;98976:5;98983:14;98959:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;98959:55:0;-1:-1:-1;;;;;98959:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;98999:14;98959:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;98959:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:55::i;:::-;98937:19;;:77;;;-1:-1:-1;;;;;98937:19:0;:77;:::i;:::-;-1:-1:-1;;;;;98936:106:0;;;;;:::i;:::-;98912:130;-1:-1:-1;72459:5:0;99169:27;98912:130;72459:5;99169:27;:::i;:::-;99150:47;;:15;:47;:::i;:::-;99149:63;;;;:::i;:::-;99131:81;;:15;:81;:::i;:::-;99115:97;-1:-1:-1;99389:22:0;99115:97;99389:6;:22;:::i;:::-;99377:34;98122:1297;-1:-1:-1;;;;;;98122:1297:0:o;105004:477::-;105106:17;:15;:17::i;:::-;105083:20;:40;105151:27;:25;:27::i;:::-;105134:14;:44;105372:27;105380:11;105393:5;105372:7;:27::i;:::-;105349:20;;;;:7;:20;;;;;;;;:50;;;;105453:20;;105410:27;:40;;;;;:63;;;;-1:-1:-1;105004:477:0:o;108693:264::-;-1:-1:-1;;;;;108761:13:0;;;;;;:9;:13;;;;;:18;;108778:1;;108761:13;:18;;108778:1;;108761:18;:::i;:::-;;;;-1:-1:-1;;108790:20:0;;;;:7;:20;;;;;;:25;;-1:-1:-1;;;;;;108790:25:0;-1:-1:-1;;;;;108790:25:0;;;;;;;;108831:37;;108790:20;;;108831:37;;108790:20;;108831:37;108887:55;108918:1;108922:2;108926:11;108887:55;;;;;;;;;;;;:22;:55::i;:::-;108879:70;;;;-1:-1:-1;;;108879:70:0;;27738:2:1;108879:70:0;;;27720:21:1;27777:1;27757:18;;;27750:29;-1:-1:-1;;;27795:18:1;;;27788:32;27837:18;;108879:70:0;27536:325:1;107103:271:0;107256:32;107266:4;107272:2;107276:11;107256:9;:32::i;:::-;107307:52;107330:4;107336:2;107340:11;107353:5;107307:22;:52::i;:::-;107299:67;;;;-1:-1:-1;;;107299:67:0;;27738:2:1;107299:67:0;;;27720:21:1;27777:1;27757:18;;;27750:29;-1:-1:-1;;;27795:18:1;;;27788:32;27837:18;;107299:67:0;27536:325:1;90118:622:0;90442:19;;90414:25;;;;90398:13;;90414:47;;;:::i;:::-;90398:63;;90472:30;90483:11;90496:5;90472:10;:30::i;:::-;90520:40;;;;:27;:40;;;;;90513:47;;;90690:11;90682:19;;:5;:19;:::i;:::-;90662:16;;:39;;;;;;;:::i;:::-;;;;-1:-1:-1;90714:18:0;;-1:-1:-1;90720:11:0;90714:5;:18::i;100155:678::-;100304:24;100330:16;72459:5;100394:57;100411:5;100418:15;100394:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;100394:57:0;-1:-1:-1;;;;;100394:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;100435:15;100394:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;100394:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:57::i;:::-;100371:20;;:80;;;-1:-1:-1;;;100371:20:0;;-1:-1:-1;;;;;100371:20:0;:80;:::i;:::-;-1:-1:-1;;;;;100370:96:0;;;;;:::i;:::-;100359:107;-1:-1:-1;72459:5:0;100584:22;100359:107;72459:5;100584:22;:::i;:::-;100565:42;;:15;:42;:::i;:::-;100564:58;;;;:::i;:::-;100546:76;;:15;:76;:::i;:::-;100535:87;;100649:13;100637:8;:25;100633:193;;-1:-1:-1;100698:1:0;;-1:-1:-1;100725:13:0;100633:193;;;100790:24;100806:8;100790:13;:24;:::i;:::-;100771:43;;100155:678;;;;;;:::o;73276:1434::-;73417:6;73445;73468:1;73452:6;:13;:17;;;;:::i;:::-;73445:25;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;73440:30:0;:1;-1:-1:-1;;;;;73440:30:0;;73436:1267;;73494:6;73517:1;73501:6;:13;:17;;;;:::i;:::-;73494:25;;;;;;;;:::i;:::-;;;;;;;73487:32;;;;73436:1267;73546:6;73553:1;73546:9;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;73541:14:0;:1;-1:-1:-1;;;;;73541:14:0;;73537:1166;;73579:6;73586:1;73579:9;;;;;;;;:::i;73537:1166::-;73621:13;73649;73681:1;73665:6;:13;:17;;;;:::i;:::-;73649:33;;73697:11;73723:248;73746:1;73730:13;73738:5;73730;:13;:::i;:::-;:17;73723:248;;;73800:1;73783:13;73791:5;73783;:13;:::i;:::-;73782:19;;;;:::i;:::-;73774:27;;:5;:27;:::i;:::-;73768:33;;73839:1;-1:-1:-1;;;;;73824:16:0;:6;73831:3;73824:11;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;73824:16:0;;73820:136;;73873:3;73865:11;;73723:248;;73820:136;73933:3;73925:11;;73723:248;;;74005:6;74012:5;74005:13;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;73989:29:0;:6;73996:5;73989:13;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;73989:29:0;;73985:707;;;74446:6;74453:5;74446:13;;;;;;;;:::i;:::-;;;;;;;74430:6;74437:5;74430:13;;;;;;;;:::i;:::-;;;;;;;:29;;;;:::i;:::-;74390:6;74397:5;74390:13;;;;;;;;:::i;:::-;;;;;;;74386:1;:17;;;;:::i;:::-;74368:6;74375:5;74368:13;;;;;;;;:::i;:::-;;;;;;;74352:6;74359:5;74352:13;;;;;;;;:::i;:::-;;;;;;;:29;;;;:::i;:::-;74351:53;;;;:::i;:::-;74350:110;;;;:::i;:::-;74313:6;74320:5;74313:13;;;;;;;;:::i;:::-;;;;;;;:147;;;;:::i;:::-;74285:175;;;;;;;73985:707;74662:6;74669:5;74662:13;;;;;;;;:::i;:::-;;;;;;;74646:6;74653:5;74646:13;;;;;;;;:::i;:::-;;;;;;;:29;;;;:::i;:::-;74606:6;74613:5;74606:13;;;;;;;;:::i;:::-;;;;;;;74602:1;:17;;;;:::i;:::-;74584:6;74591:5;74584:13;;;;;;;;:::i;:::-;;;;;;;74568:6;74575:5;74568:13;;;;;;;;:::i;:::-;;;;;;;:29;;;;:::i;:::-;74567:53;;;;:::i;:::-;74566:110;;;;:::i;:::-;74529:6;74536:5;74529:13;;;;;;;;:::i;:::-;;;;;;;:147;;;;:::i;93949:1160::-;94068:21;94091:30;94272:17;94344:4;94321:9;:19;;;94293:9;:25;;;:47;;;;:::i;:::-;94292:56;;;;:::i;:::-;94272:76;;94599:9;:16;;;94571:9;:25;;;:44;;;;:::i;:::-;94558:9;:57;94554:548;;94633:1;94617:17;;94554:548;;;94941:9;94922;:16;;;94894:9;:25;;;:44;;;;:::i;:::-;:56;;;;:::i;:::-;95028:17;;95000:25;;;;94878:72;;-1:-1:-1;95000:45:0;;-1:-1:-1;;;;;95028:17:0;;;;95000:45;:::i;:::-;94969:27;72459:5;94969:13;:27;:::i;:::-;:76;94965:125;;95089:1;95064:26;;94965:125;94128:981;93949:1160;;;;;:::o;96936:520::-;97015:12;97177:25;72459:5;97239:13;;;;;;;;;-1:-1:-1;;;;;97239:13:0;-1:-1:-1;;;;;97206:46:0;:13;;;;;;;;;-1:-1:-1;;;;;97206:13:0;-1:-1:-1;;;;;97206:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:46;;;;:::i;:::-;97205:62;;;;:::i;:::-;97177:90;;97303:17;97282:18;:38;97278:170;;;97387:17;97351:32;72459:5;97351:18;:32;:::i;:::-;97350:54;;;;:::i;:::-;97335:70;;97278:170;;;72459:5;97421:27;;97278:170;97029:427;96936:520;;;:::o;37009:716::-;37433:23;37459:69;37487:4;37459:69;;;;;;;;;;;;;;;;;37467:5;-1:-1:-1;;;;;37459:27:0;;;:69;;;;;:::i;:::-;37543:17;;37433:95;;-1:-1:-1;37543:21:0;37539:179;;37640:10;37629:30;;;;;;;;;;;;:::i;:::-;37621:85;;;;-1:-1:-1;;;37621:85:0;;33473:2:1;37621:85:0;;;33455:21:1;33512:2;33492:18;;;33485:30;33551:34;33531:18;;;33524:62;-1:-1:-1;;;33602:18:1;;;33595:40;33652:19;;37621:85:0;33271:406:1;39386:451:0;39461:13;39487:19;39519:10;39523:6;39519:1;:10;:::i;:::-;:14;;39532:1;39519:14;:::i;:::-;-1:-1:-1;;;;;39509:25:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;39509:25:0;;39487:47;;-1:-1:-1;;;39545:6:0;39552:1;39545:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;39545:15:0;;;;;;;;;-1:-1:-1;;;39571:6:0;39578:1;39571:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;39571:15:0;;;;;;;;-1:-1:-1;39602:9:0;39614:10;39618:6;39614:1;:10;:::i;:::-;:14;;39627:1;39614:14;:::i;:::-;39602:26;;39597:135;39634:1;39630;:5;39597:135;;;-1:-1:-1;;;39682:5:0;39690:3;39682:11;39669:25;;;;;;;:::i;:::-;;;;39657:6;39664:1;39657:9;;;;;;;;:::i;:::-;;;;:37;-1:-1:-1;;;;;39657:37:0;;;;;;;;-1:-1:-1;39719:1:0;39709:11;;;;;39637:3;;;:::i;:::-;;;39597:135;;;-1:-1:-1;39750:10:0;;39742:55;;;;-1:-1:-1;;;39742:55:0;;24643:2:1;39742:55:0;;;24625:21:1;;;24662:18;;;24655:30;24721:34;24701:18;;;24694:62;24773:18;;39742:55:0;24441:356:1;101112:202:0;101172:7;101192:19;101232:12;;101214:15;:30;:63;;101265:12;;101214:63;;;101247:15;101192:85;101112:202;-1:-1:-1;;101112:202:0:o;2726:65::-;1592:13;;;;;;;;:30;;-1:-1:-1;1610:12:0;;;;1609:13;1592:30;1584:89;;;;-1:-1:-1;;;1584:89:0;;;;;;;:::i;:::-;1709:13;;;;;;;1708:14;1733:101;;;;1768:13;:20;;-1:-1:-1;;1803:19:0;;;;;1860:68;;;;1895:13;:21;;-1:-1:-1;;1895:21:0;;;1573:362;2726:65::o;4176:92::-;1592:13;;;;;;;;:30;;-1:-1:-1;1610:12:0;;;;1609:13;1592:30;1584:89;;;;-1:-1:-1;;;1584:89:0;;;;;;;:::i;:::-;1709:13;;;;;;;1708:14;1733:101;;;;1768:13;:20;;-1:-1:-1;;1803:19:0;;;;;1733:101;4245:7:::1;:15:::0;;-1:-1:-1;;4245:15:0::1;::::0;;1860:68;;;;1895:13;:21;;-1:-1:-1;;1895:21:0;;;1573:362;4176:92::o;110958:884::-;111117:4;-1:-1:-1;;;;;111138:13:0;;26793:20;26841:8;111134:701;;111174:85;;-1:-1:-1;;;111174:85:0;;-1:-1:-1;;;;;111174:47:0;;;;;:85;;111222:10;;111234:4;;111240:11;;111253:5;;111174:85;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;111174:85:0;;;;;;;;-1:-1:-1;;111174:85:0;;;;;;;;;;;;:::i;:::-;;;111170:610;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;111476:13:0;;111472:293;;111519:12;;-1:-1:-1;;;111519:12:0;;27738:2:1;111519:12:0;;;27720:21:1;27777:1;27757:18;;;27750:29;-1:-1:-1;;;27795:18:1;;;27788:32;27837:18;;111519:12:0;27536:325:1;111472:293:0;111715:6;111709:13;111700:6;111696:2;111692:15;111685:38;111170:610;-1:-1:-1;;;;;;111342:66:0;-1:-1:-1;;;111342:66:0;;-1:-1:-1;111335:73:0;;111134:701;-1:-1:-1;111819:4:0;110958:884;;;;;;:::o;109083:349::-;109139:13;109155:21;109164:11;109155:8;:21::i;:::-;109139:37;;109217:33;109234:1;109238:11;109217:8;:33::i;:::-;-1:-1:-1;;;;;109263:16:0;;;;;;:9;:16;;;;;:21;;109283:1;;109263:16;:21;;109283:1;;109263:21;:::i;:::-;;;;-1:-1:-1;;109302:20:0;;;;:7;:20;;;;;;;;109295:27;;-1:-1:-1;;;;;;109295:27:0;;;109340:13;:26;;;;;;109333:33;;;109295:27;109333:33;;;;;;;;;;;;;;;;109384:40;109310:11;;109302:20;-1:-1:-1;;;;;109384:40:0;;;;;109302:20;;109384:40;109128:304;109083:349;:::o;29276:229::-;29413:12;29445:52;29467:6;29475:4;29481:1;29484:12;29413;26793:20;;30683:60;;;;-1:-1:-1;;;30683:60:0;;32456:2:1;30683:60:0;;;32438:21:1;32495:2;32475:18;;;32468:30;32534:31;32514:18;;;32507:59;32583:18;;30683:60:0;32254:353:1;30683:60:0;30757:12;30771:23;30798:6;-1:-1:-1;;;;;30798:11:0;30817:5;30824:4;30798:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30756:73;;;;30847:51;30864:7;30873:10;30885:12;30847:16;:51::i;:::-;30840:58;30396:510;-1:-1:-1;;;;;;;30396:510:0:o;33082:712::-;33232:12;33261:7;33257:530;;;-1:-1:-1;33292:10:0;33285:17;;33257:530;33406:17;;:21;33402:374;;33604:10;33598:17;33665:15;33652:10;33648:2;33644:19;33637:44;33402:374;33747:12;33740:20;;-1:-1:-1;;;33740:20:0;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:406:1;78:5;-1:-1:-1;;;;;104:6:1;101:30;98:56;;;134:18;;:::i;:::-;172:57;217:2;196:15;;-1:-1:-1;;192:29:1;223:4;188:40;172:57;:::i;:::-;163:66;;252:6;245:5;238:21;292:3;283:6;278:3;274:16;271:25;268:45;;;309:1;306;299:12;268:45;358:6;353:3;346:4;339:5;335:16;322:43;412:1;405:4;396:6;389:5;385:18;381:29;374:40;14:406;;;;;:::o;425:134::-;493:20;;522:31;493:20;522:31;:::i;564:677::-;617:5;670:3;663:4;655:6;651:17;647:27;637:55;;688:1;685;678:12;637:55;724:6;711:20;750:4;774:60;790:43;830:2;790:43;:::i;:::-;774:60;:::i;:::-;856:3;880:2;875:3;868:15;908:2;903:3;899:12;892:19;;943:2;935:6;931:15;995:3;990:2;984;981:1;977:10;969:6;965:23;961:32;958:41;955:61;;;1012:1;1009;1002:12;955:61;1034:1;1044:168;1058:2;1055:1;1052:9;1044:168;;;1115:22;1133:3;1115:22;:::i;:::-;1103:35;;1158:12;;;;1190;;;;1076:1;1069:9;1044:168;;;-1:-1:-1;1230:5:1;;564:677;-1:-1:-1;;;;;;;564:677:1:o;1246:171::-;1313:20;;-1:-1:-1;;;;;1362:30:1;;1352:41;;1342:69;;1407:1;1404;1397:12;1422:247;1481:6;1534:2;1522:9;1513:7;1509:23;1505:32;1502:52;;;1550:1;1547;1540:12;1502:52;1589:9;1576:23;1608:31;1633:5;1608:31;:::i;1674:251::-;1744:6;1797:2;1785:9;1776:7;1772:23;1768:32;1765:52;;;1813:1;1810;1803:12;1765:52;1845:9;1839:16;1864:31;1889:5;1864:31;:::i;1930:388::-;1998:6;2006;2059:2;2047:9;2038:7;2034:23;2030:32;2027:52;;;2075:1;2072;2065:12;2027:52;2114:9;2101:23;2133:31;2158:5;2133:31;:::i;:::-;2183:5;-1:-1:-1;2240:2:1;2225:18;;2212:32;2253:33;2212:32;2253:33;:::i;:::-;2305:7;2295:17;;;1930:388;;;;;:::o;2323:456::-;2400:6;2408;2416;2469:2;2457:9;2448:7;2444:23;2440:32;2437:52;;;2485:1;2482;2475:12;2437:52;2524:9;2511:23;2543:31;2568:5;2543:31;:::i;:::-;2593:5;-1:-1:-1;2650:2:1;2635:18;;2622:32;2663:33;2622:32;2663:33;:::i;:::-;2323:456;;2715:7;;-1:-1:-1;;;2769:2:1;2754:18;;;;2741:32;;2323:456::o;2784:794::-;2879:6;2887;2895;2903;2956:3;2944:9;2935:7;2931:23;2927:33;2924:53;;;2973:1;2970;2963:12;2924:53;3012:9;2999:23;3031:31;3056:5;3031:31;:::i;:::-;3081:5;-1:-1:-1;3138:2:1;3123:18;;3110:32;3151:33;3110:32;3151:33;:::i;:::-;3203:7;-1:-1:-1;3257:2:1;3242:18;;3229:32;;-1:-1:-1;3312:2:1;3297:18;;3284:32;-1:-1:-1;;;;;3328:30:1;;3325:50;;;3371:1;3368;3361:12;3325:50;3394:22;;3447:4;3439:13;;3435:27;-1:-1:-1;3425:55:1;;3476:1;3473;3466:12;3425:55;3499:73;3564:7;3559:2;3546:16;3541:2;3537;3533:11;3499:73;:::i;:::-;3489:83;;;2784:794;;;;;;;:::o;3583:382::-;3648:6;3656;3709:2;3697:9;3688:7;3684:23;3680:32;3677:52;;;3725:1;3722;3715:12;3677:52;3764:9;3751:23;3783:31;3808:5;3783:31;:::i;:::-;3833:5;-1:-1:-1;3890:2:1;3875:18;;3862:32;3903:30;3862:32;3903:30;:::i;3970:315::-;4038:6;4046;4099:2;4087:9;4078:7;4074:23;4070:32;4067:52;;;4115:1;4112;4105:12;4067:52;4154:9;4141:23;4173:31;4198:5;4173:31;:::i;:::-;4223:5;4275:2;4260:18;;;;4247:32;;-1:-1:-1;;;3970:315:1:o;4290:521::-;4385:6;4393;4401;4409;4417;4470:3;4458:9;4449:7;4445:23;4441:33;4438:53;;;4487:1;4484;4477:12;4438:53;4526:9;4513:23;4545:31;4570:5;4545:31;:::i;:::-;4595:5;4647:2;4632:18;;4619:32;;-1:-1:-1;4698:2:1;4683:18;;4670:32;;4749:2;4734:18;;4721:32;;-1:-1:-1;4800:3:1;4785:19;4772:33;;-1:-1:-1;4290:521:1;-1:-1:-1;;;4290:521:1:o;4816:1238::-;4963:6;4971;4979;4987;5040:3;5028:9;5019:7;5015:23;5011:33;5008:53;;;5057:1;5054;5047:12;5008:53;5097:9;5084:23;-1:-1:-1;;;;;5122:6:1;5119:30;5116:50;;;5162:1;5159;5152:12;5116:50;5185:22;;5238:4;5230:13;;5226:27;-1:-1:-1;5216:55:1;;5267:1;5264;5257:12;5216:55;5303:2;5290:16;5325:4;5349:60;5365:43;5405:2;5365:43;:::i;5349:60::-;5431:3;5455:2;5450:3;5443:15;5483:2;5478:3;5474:12;5467:19;;5514:2;5510;5506:11;5562:7;5557:2;5551;5548:1;5544:10;5540:2;5536:19;5532:28;5529:41;5526:61;;;5583:1;5580;5573:12;5526:61;5605:1;5596:10;;5615:238;5629:2;5626:1;5623:9;5615:238;;;5700:3;5687:17;5717:31;5742:5;5717:31;:::i;:::-;5761:18;;5647:1;5640:9;;;;;5799:12;;;;5831;;5615:238;;;-1:-1:-1;5872:5:1;-1:-1:-1;5896:38:1;;-1:-1:-1;5915:18:1;;;5896:38;:::i;:::-;5886:48;;;;;5953:38;5987:2;5976:9;5972:18;5953:38;:::i;:::-;5943:48;;6010:38;6044:2;6033:9;6029:18;6010:38;:::i;:::-;6000:48;;4816:1238;;;;;;;:::o;6059:902::-;6143:6;6174:2;6217;6205:9;6196:7;6192:23;6188:32;6185:52;;;6233:1;6230;6223:12;6185:52;6273:9;6260:23;-1:-1:-1;;;;;6298:6:1;6295:30;6292:50;;;6338:1;6335;6328:12;6292:50;6361:22;;6414:4;6406:13;;6402:27;-1:-1:-1;6392:55:1;;6443:1;6440;6433:12;6392:55;6479:2;6466:16;6502:60;6518:43;6558:2;6518:43;:::i;6502:60::-;6584:3;6608:2;6603:3;6596:15;6636:2;6631:3;6627:12;6620:19;;6667:2;6663;6659:11;6715:7;6710:2;6704;6701:1;6697:10;6693:2;6689:19;6685:28;6682:41;6679:61;;;6736:1;6733;6726:12;6679:61;6758:1;6749:10;;6768:163;6782:2;6779:1;6776:9;6768:163;;;6839:17;;6827:30;;6800:1;6793:9;;;;;6877:12;;;;6909;;6768:163;;;-1:-1:-1;6950:5:1;6059:902;-1:-1:-1;;;;;;;6059:902:1:o;6966:591::-;7082:6;7090;7143:2;7131:9;7122:7;7118:23;7114:32;7111:52;;;7159:1;7156;7149:12;7111:52;7199:9;7186:23;-1:-1:-1;;;;;7269:2:1;7261:6;7258:14;7255:34;;;7285:1;7282;7275:12;7255:34;7308:60;7360:7;7351:6;7340:9;7336:22;7308:60;:::i;:::-;7298:70;;7421:2;7410:9;7406:18;7393:32;7377:48;;7450:2;7440:8;7437:16;7434:36;;;7466:1;7463;7456:12;7434:36;;7489:62;7543:7;7532:8;7521:9;7517:24;7489:62;:::i;:::-;7479:72;;;6966:591;;;;;:::o;7562:722::-;7685:6;7693;7701;7754:2;7742:9;7733:7;7729:23;7725:32;7722:52;;;7770:1;7767;7760:12;7722:52;7810:9;7797:23;-1:-1:-1;;;;;7880:2:1;7872:6;7869:14;7866:34;;;7896:1;7893;7886:12;7866:34;7919:60;7971:7;7962:6;7951:9;7947:22;7919:60;:::i;:::-;7909:70;;8032:2;8021:9;8017:18;8004:32;7988:48;;8061:2;8051:8;8048:16;8045:36;;;8077:1;8074;8067:12;8045:36;;8100:62;8154:7;8143:8;8132:9;8128:24;8100:62;:::i;:::-;8090:72;;;8212:2;8201:9;8197:18;8184:32;8225:29;8248:5;8225:29;:::i;:::-;8273:5;8263:15;;;7562:722;;;;;:::o;8289:245::-;8356:6;8409:2;8397:9;8388:7;8384:23;8380:32;8377:52;;;8425:1;8422;8415:12;8377:52;8457:9;8451:16;8476:28;8498:5;8476:28;:::i;8539:180::-;8598:6;8651:2;8639:9;8630:7;8626:23;8622:32;8619:52;;;8667:1;8664;8657:12;8619:52;-1:-1:-1;8690:23:1;;8539:180;-1:-1:-1;8539:180:1:o;8724:315::-;8792:6;8800;8853:2;8841:9;8832:7;8828:23;8824:32;8821:52;;;8869:1;8866;8859:12;8821:52;8905:9;8892:23;8882:33;;8965:2;8954:9;8950:18;8937:32;8978:31;9003:5;8978:31;:::i;9044:245::-;9102:6;9155:2;9143:9;9134:7;9130:23;9126:32;9123:52;;;9171:1;9168;9161:12;9123:52;9210:9;9197:23;9229:30;9253:5;9229:30;:::i;9294:249::-;9363:6;9416:2;9404:9;9395:7;9391:23;9387:32;9384:52;;;9432:1;9429;9422:12;9384:52;9464:9;9458:16;9483:30;9507:5;9483:30;:::i;10516:450::-;10585:6;10638:2;10626:9;10617:7;10613:23;10609:32;10606:52;;;10654:1;10651;10644:12;10606:52;10694:9;10681:23;-1:-1:-1;;;;;10719:6:1;10716:30;10713:50;;;10759:1;10756;10749:12;10713:50;10782:22;;10835:4;10827:13;;10823:27;-1:-1:-1;10813:55:1;;10864:1;10861;10854:12;10813:55;10887:73;10952:7;10947:2;10934:16;10929:2;10925;10921:11;10887:73;:::i;11156:184::-;11226:6;11279:2;11267:9;11258:7;11254:23;11250:32;11247:52;;;11295:1;11292;11285:12;11247:52;-1:-1:-1;11318:16:1;;11156:184;-1:-1:-1;11156:184:1:o;11665:383::-;11742:6;11750;11758;11811:2;11799:9;11790:7;11786:23;11782:32;11779:52;;;11827:1;11824;11817:12;11779:52;11863:9;11850:23;11840:33;;11923:2;11912:9;11908:18;11895:32;11936:31;11961:5;11936:31;:::i;12053:248::-;12121:6;12129;12182:2;12170:9;12161:7;12157:23;12153:32;12150:52;;;12198:1;12195;12188:12;12150:52;-1:-1:-1;;12221:23:1;;;12291:2;12276:18;;;12263:32;;-1:-1:-1;12053:248:1:o;12306:245::-;12385:6;12393;12446:2;12434:9;12425:7;12421:23;12417:32;12414:52;;;12462:1;12459;12452:12;12414:52;-1:-1:-1;;12485:16:1;;12541:2;12526:18;;;12520:25;12485:16;;12520:25;;-1:-1:-1;12306:245:1:o;12556:383::-;12633:6;12641;12649;12702:2;12690:9;12681:7;12677:23;12673:32;12670:52;;;12718:1;12715;12708:12;12670:52;12754:9;12741:23;12731:33;;12811:2;12800:9;12796:18;12783:32;12773:42;;12865:2;12854:9;12850:18;12837:32;12878:31;12903:5;12878:31;:::i;12944:184::-;13002:6;13055:2;13043:9;13034:7;13030:23;13026:32;13023:52;;;13071:1;13068;13061:12;13023:52;13094:28;13112:9;13094:28;:::i;13133:256::-;13199:6;13207;13260:2;13248:9;13239:7;13235:23;13231:32;13228:52;;;13276:1;13273;13266:12;13228:52;13299:28;13317:9;13299:28;:::i;:::-;13289:38;;13346:37;13379:2;13368:9;13364:18;13346:37;:::i;:::-;13336:47;;13133:256;;;;;:::o;13394:247::-;13462:6;13515:2;13503:9;13494:7;13490:23;13486:32;13483:52;;;13531:1;13528;13521:12;13483:52;13563:9;13557:16;13582:29;13605:5;13582:29;:::i;13778:459::-;13830:3;13868:5;13862:12;13895:6;13890:3;13883:19;13921:4;13950:2;13945:3;13941:12;13934:19;;13987:2;13980:5;13976:14;14008:1;14018:194;14032:6;14029:1;14026:13;14018:194;;;14097:13;;-1:-1:-1;;;;;14093:38:1;14081:51;;14152:12;;;;14187:15;;;;14054:1;14047:9;14018:194;;;-1:-1:-1;14228:3:1;;13778:459;-1:-1:-1;;;;;13778:459:1:o;14242:1706::-;14334:12;;37349:19;;;14302:3;37186:14;;;37401:4;37217:18;;;37392:14;;;14302:3;;14334:12;14302:3;14533:581;14573:6;14569:1;14556:11;14552:19;14549:31;14533:581;;;14682:13;;-1:-1:-1;;;;;14767:13:1;;;16468:43;;14809:2;14846:13;;;14842:22;;14875:4;14866:14;;16468:43;14904:3;14942:13;;;14938:22;;;14962:12;;;16468:43;15010:3;15006:14;;;;15031:2;15022:12;;16468:43;15055:12;;;;15102:1;15090:14;;;;14635:1;14618:19;14533:581;;;15137:13;;;15162:23;;;15159:195;;;-1:-1:-1;;;;;15226:31:1;;16468:43;;15292:4;15283:14;;;;15342:1;15325:19;15159:195;15382:6;15369:11;15366:23;15363:204;;;-1:-1:-1;;;;;15438:2:1;15434:15;;;15430:40;16468:43;;15505:4;15496:14;;;;15555:1;15538:19;15363:204;15595:6;15582:11;15579:23;15576:205;;;-1:-1:-1;;;;;15651:3:1;15647:16;;;15643:41;16468:43;;15719:4;15710:14;;;;15769:1;15752:19;15576:205;15809:6;15796:11;15793:23;15790:133;;;15861:3;15857:16;;;16468:43;;15908:4;15903:3;15899:14;15892:21;;15790:133;-1:-1:-1;15939:3:1;;14242:1706;-1:-1:-1;;;;14242:1706:1:o;15953:268::-;16005:3;16043:5;16037:12;16070:6;16065:3;16058:19;16086:63;16142:6;16135:4;16130:3;16126:14;16119:4;16112:5;16108:16;16086:63;:::i;:::-;16203:2;16182:15;-1:-1:-1;;16178:29:1;16169:39;;;;16210:4;16165:50;;15953:268;-1:-1:-1;;15953:268:1:o;16226:184::-;16267:3;16305:5;16299:12;16320:52;16365:6;16360:3;16353:4;16346:5;16342:16;16320:52;:::i;:::-;16388:16;;;;;16226:184;-1:-1:-1;;16226:184:1:o;16522:274::-;16651:3;16689:6;16683:13;16705:53;16751:6;16746:3;16739:4;16731:6;16727:17;16705:53;:::i;:::-;16774:16;;;;;16522:274;-1:-1:-1;;16522:274:1:o;16801:1183::-;16977:3;17006:1;17039:6;17033:13;17069:3;17091:1;17119:9;17115:2;17111:18;17101:28;;17179:2;17168:9;17164:18;17201;17191:61;;17245:4;17237:6;17233:17;17223:27;;17191:61;17271:2;17319;17311:6;17308:14;17288:18;17285:38;17282:165;;;-1:-1:-1;;;17346:33:1;;17402:4;17399:1;17392:15;17432:4;17353:3;17420:17;17282:165;17463:18;17490:104;;;;17608:1;17603:330;;;;17456:477;;17490:104;-1:-1:-1;;17523:24:1;;17511:37;;17568:16;;;;-1:-1:-1;17490:104:1;;17603:330;37193:1;37186:14;;;37230:4;37217:18;;17708:1;17722:165;17736:6;17733:1;17730:13;17722:165;;;17814:14;;17801:11;;;17794:35;17857:16;;;;17751:10;;17722:165;;;17726:3;;17916:6;17911:3;17907:16;17900:23;;17456:477;;;;;;;17949:29;17974:3;17966:6;17949:29;:::i;17989:786::-;18400:25;18395:3;18388:38;18370:3;18455:6;18449:13;18471:62;18526:6;18521:2;18516:3;18512:12;18505:4;18497:6;18493:17;18471:62;:::i;:::-;-1:-1:-1;;;18592:2:1;18552:16;;;18584:11;;;18577:40;18642:13;;18664:63;18642:13;18713:2;18705:11;;18698:4;18686:17;;18664:63;:::i;:::-;18747:17;18766:2;18743:26;;17989:786;-1:-1:-1;;;;17989:786:1:o;19414:522::-;19608:4;-1:-1:-1;;;;;19718:2:1;19710:6;19706:15;19695:9;19688:34;19770:2;19762:6;19758:15;19753:2;19742:9;19738:18;19731:43;;19810:6;19805:2;19794:9;19790:18;19783:34;19853:3;19848:2;19837:9;19833:18;19826:31;19874:56;19925:3;19914:9;19910:19;19902:6;19874:56;:::i;20243:1495::-;20613:3;20626:22;;;20697:13;;20598:19;;;20719:22;;;20565:4;;20795;;20772:3;20757:19;;;20822:15;;;20565:4;20865:169;20879:6;20876:1;20873:13;20865:169;;;20940:13;;20928:26;;20974:12;;;;21009:15;;;;20901:1;20894:9;20865:169;;;-1:-1:-1;;;21070:19:1;;;21050:18;;;21043:47;21140:13;;21162:21;;;21238:15;;;;21201:12;;;21273:1;21283:327;21299:8;21294:3;21291:17;21283:327;;;21364:15;;21410:9;;-1:-1:-1;;;;;21406:58:1;21392:73;;21507:11;;21501:18;21485:14;;;21478:42;21583:17;;;;21553:4;21542:16;;;;21327:1;21318:11;21283:327;;;-1:-1:-1;;;;;;;13712:54:1;;21683:4;21668:20;;13700:67;21627:5;-1:-1:-1;21641:48:1;;-1:-1:-1;;13646:127:1;21641:48;21725:6;21720:2;21709:9;21705:18;21698:34;20243:1495;;;;;;;:::o;21743:537::-;22020:2;22009:9;22002:21;21983:4;22046:55;22097:2;22086:9;22082:18;22074:6;22046:55;:::i;:::-;22149:9;22141:6;22137:22;22132:2;22121:9;22117:18;22110:50;22177:43;22213:6;22205;22177:43;:::i;:::-;22169:51;;;22268:4;22260:6;22256:17;22251:2;22240:9;22236:18;22229:45;21743:537;;;;;;:::o;22285:469::-;22532:2;22521:9;22514:21;22495:4;22558:63;22617:2;22606:9;22602:18;22594:6;22558:63;:::i;:::-;22669:9;22661:6;22657:22;22652:2;22641:9;22637:18;22630:50;22697:51;22741:6;22733;22697:51;:::i;23877:230::-;24026:2;24015:9;24008:21;23989:4;24046:55;24097:2;24086:9;24082:18;24074:6;24046:55;:::i;27866:340::-;28068:2;28050:21;;;28107:2;28087:18;;;28080:30;-1:-1:-1;;;28141:2:1;28126:18;;28119:46;28197:2;28182:18;;27866:340::o;29201:410::-;29403:2;29385:21;;;29442:2;29422:18;;;29415:30;29481:34;29476:2;29461:18;;29454:62;-1:-1:-1;;;29547:2:1;29532:18;;29525:44;29601:3;29586:19;;29201:410::o;31925:324::-;32127:2;32109:21;;;32166:1;32146:18;;;32139:29;-1:-1:-1;;;32199:2:1;32184:18;;32177:31;32240:2;32225:18;;31925:324::o;34670:325::-;34872:2;34854:21;;;34911:1;34891:18;;;34884:29;-1:-1:-1;;;34944:2:1;34929:18;;34922:32;34986:2;34971:18;;34670:325::o;36642:275::-;36713:2;36707:9;36778:2;36759:13;;-1:-1:-1;;36755:27:1;36743:40;;-1:-1:-1;;;;;36798:34:1;;36834:22;;;36795:62;36792:88;;;36860:18;;:::i;:::-;36896:2;36889:22;36642:275;;-1:-1:-1;36642:275:1:o;36922:183::-;36982:4;-1:-1:-1;;;;;37007:6:1;37004:30;37001:56;;;37037:18;;:::i;:::-;-1:-1:-1;37082:1:1;37078:14;37094:4;37074:25;;36922:183::o;37417:128::-;37457:3;37488:1;37484:6;37481:1;37478:13;37475:39;;;37494:18;;:::i;:::-;-1:-1:-1;37530:9:1;;37417:128::o;37550:236::-;37589:3;-1:-1:-1;;;;;37662:2:1;37659:1;37655:10;37692:2;37689:1;37685:10;37723:3;37719:2;37715:12;37710:3;37707:21;37704:47;;;37731:18;;:::i;:::-;37767:13;;37550:236;-1:-1:-1;;;;37550:236:1:o;37791:120::-;37831:1;37857;37847:35;;37862:18;;:::i;:::-;-1:-1:-1;37896:9:1;;37791:120::o;37916:199::-;37955:1;-1:-1:-1;;;;;38026:2:1;38023:1;38019:10;38048:3;38038:37;;38055:18;;:::i;:::-;38093:10;;38089:20;;;;;37916:199;-1:-1:-1;;37916:199:1:o;38120:422::-;38209:1;38252:5;38209:1;38266:270;38287:7;38277:8;38274:21;38266:270;;;38346:4;38342:1;38338:6;38334:17;38328:4;38325:27;38322:53;;;38355:18;;:::i;:::-;38405:7;38395:8;38391:22;38388:55;;;38425:16;;;;38388:55;38504:22;;;;38464:15;;;;38266:270;;38547:140;38605:5;38634:47;38675:4;38665:8;38661:19;38655:4;38741:5;38771:8;38761:80;;-1:-1:-1;38812:1:1;38826:5;;38761:80;38860:4;38850:76;;-1:-1:-1;38897:1:1;38911:5;;38850:76;38942:4;38960:1;38955:59;;;;39028:1;39023:130;;;;38935:218;;38955:59;38985:1;38976:10;;38999:5;;;39023:130;39060:3;39050:8;39047:17;39044:43;;;39067:18;;:::i;:::-;-1:-1:-1;;39123:1:1;39109:16;;39138:5;;38935:218;;39237:2;39227:8;39224:16;39218:3;39212:4;39209:13;39205:36;39199:2;39189:8;39186:16;39181:2;39175:4;39172:12;39168:35;39165:77;39162:159;;;-1:-1:-1;39274:19:1;;;39306:5;;39162:159;39353:34;39378:8;39372:4;39353:34;:::i;:::-;39423:6;39419:1;39415:6;39411:19;39402:7;39399:32;39396:58;;;39434:18;;:::i;:::-;39472:20;;38692:806;-1:-1:-1;;;38692:806:1:o;39503:168::-;39543:7;39609:1;39605;39601:6;39597:14;39594:1;39591:21;39586:1;39579:9;39572:17;39568:45;39565:71;;;39616:18;;:::i;:::-;-1:-1:-1;39656:9:1;;39503:168::o;39676:270::-;39715:7;-1:-1:-1;;;;;39792:2:1;39789:1;39785:10;39822:2;39819:1;39815:10;39878:3;39874:2;39870:12;39865:3;39862:21;39855:3;39848:11;39841:19;39837:47;39834:73;;;39887:18;;:::i;:::-;39927:13;;39676:270;-1:-1:-1;;;;39676:270:1:o;39951:125::-;39991:4;40019:1;40016;40013:8;40010:34;;;40024:18;;:::i;:::-;-1:-1:-1;40061:9:1;;39951:125::o;40081:229::-;40120:4;-1:-1:-1;;;;;40217:10:1;;;;40187;;40239:12;;;40236:38;;;40254:18;;:::i;:::-;40291:13;;40081:229;-1:-1:-1;;;40081:229:1:o;40315:258::-;40387:1;40397:113;40411:6;40408:1;40405:13;40397:113;;;40487:11;;;40481:18;40468:11;;;40461:39;40433:2;40426:10;40397:113;;;40528:6;40525:1;40522:13;40519:48;;;-1:-1:-1;;40563:1:1;40545:16;;40538:27;40315:258::o;40578:136::-;40617:3;40645:5;40635:39;;40654:18;;:::i;:::-;-1:-1:-1;;;40690:18:1;;40578:136::o;40719:380::-;40798:1;40794:12;;;;40841;;;40862:61;;40916:4;40908:6;40904:17;40894:27;;40862:61;40969:2;40961:6;40958:14;40938:18;40935:38;40932:161;;;41015:10;41010:3;41006:20;41003:1;40996:31;41050:4;41047:1;41040:15;41078:4;41075:1;41068:15;41104:135;41143:3;-1:-1:-1;;41164:17:1;;41161:43;;;41184:18;;:::i;:::-;-1:-1:-1;41231:1:1;41220:13;;41104:135::o;41244:112::-;41276:1;41302;41292:35;;41307:18;;:::i;:::-;-1:-1:-1;41341:9:1;;41244:112::o;41361:127::-;41422:10;41417:3;41413:20;41410:1;41403:31;41453:4;41450:1;41443:15;41477:4;41474:1;41467:15;41493:127;41554:10;41549:3;41545:20;41542:1;41535:31;41585:4;41582:1;41575:15;41609:4;41606:1;41599:15;41625:127;41686:10;41681:3;41677:20;41674:1;41667:31;41717:4;41714:1;41707:15;41741:4;41738:1;41731:15;41757:127;41818:10;41813:3;41809:20;41806:1;41799:31;41849:4;41846:1;41839:15;41873:4;41870:1;41863:15;41889:154;-1:-1:-1;;;;;41968:5:1;41964:54;41957:5;41954:65;41944:93;;42033:1;42030;42023:12;42048:118;42134:5;42127:13;42120:21;42113:5;42110:32;42100:60;;42156:1;42153;42146:12;42171:131;-1:-1:-1;;;;;;42245:32:1;;42235:43;;42225:71;;42292:1;42289;42282:12;42307:114;42391:4;42384:5;42380:16;42373:5;42370:27;42360:55;;42411:1;42408;42401:12

Swarm Source

ipfs://45840058006f230868797238b1a0691e6a0b163718211cd780d1fcfd01a5532c

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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