ETH Price: $3,474.32 (+1.95%)
Gas: 9 Gwei

Token

SUN (SUN)
 

Overview

Max Total Supply

10,000 SUN

Holders

35

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
0xec0cb6d23f385c9818a48e0062b382adfef20a79
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
ERC_X

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2024-02-26
*/

/**
 *Submitted for verification at Etherscan.io on 2024-02-26
*/

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @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 `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

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


/**
 * @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);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}


/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the value of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155Received} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external;
}

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 */
interface IERC1155MetadataURI is IERC1155 {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @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`.
     *
     * 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;

    /**
     * @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 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: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * 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 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 address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

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

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


/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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


/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
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);
}

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}


/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        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_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

/**
 * @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 Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}


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

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @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 or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * 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.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @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`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // 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
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}














/// @notice Library for bit twiddling and boolean operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)
/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)
library LibBit {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  BIT TWIDDLING OPERATIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Find last set.
    /// Returns the index of the most significant bit of `x`,
    /// counting from the least significant bit position.
    /// If `x` is zero, returns 256.
    function fls(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x)))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0x0706060506020504060203020504030106050205030304010505030400000000))
        }
    }

    /// @dev Count leading zeros.
    /// Returns the number of zeros preceding the most significant one bit.
    /// If `x` is zero, returns 256.
    function clz(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))
        }
    }

    /// @dev Find first set.
    /// Returns the index of the least significant bit of `x`,
    /// counting from the least significant bit position.
    /// If `x` is zero, returns 256.
    /// Equivalent to `ctz` (count trailing zeros), which gives
    /// the number of zeros following the least significant one bit.
    function ffs(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Isolate the least significant bit.
            let b := and(x, add(not(x), 1))

            r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, b)))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, b))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, b))))

            // For the remaining 32 bits, use a De Bruijn lookup.
            // forgefmt: disable-next-item
            r := or(r, byte(and(div(0xd76453e0, shr(r, b)), 0x1f),
                0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
        }
    }

    /// @dev Returns the number of set bits in `x`.
    function popCount(uint256 x) internal pure returns (uint256 c) {
        /// @solidity memory-safe-assembly
        assembly {
            let max := not(0)
            let isMax := eq(x, max)
            x := sub(x, and(shr(1, x), div(max, 3)))
            x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))
            x := and(add(x, shr(4, x)), div(max, 17))
            c := or(shl(8, isMax), shr(248, mul(x, div(max, 255))))
        }
    }

    /// @dev Returns whether `x` is a power of 2.
    function isPo2(uint256 x) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `x && !(x & (x - 1))`.
            result := iszero(add(and(x, sub(x, 1)), iszero(x)))
        }
    }

    /// @dev Returns `x` reversed at the bit level.
    function reverseBits(uint256 x) internal pure returns (uint256 r) {
        uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;
        uint256 m1 = m0 ^ (m0 << 2);
        uint256 m2 = m1 ^ (m1 << 1);
        r = reverseBytes(x);
        r = (m2 & (r >> 1)) | ((m2 & r) << 1);
        r = (m1 & (r >> 2)) | ((m1 & r) << 2);
        r = (m0 & (r >> 4)) | ((m0 & r) << 4);
    }

    /// @dev Returns `x` reversed at the byte level.
    function reverseBytes(uint256 x) internal pure returns (uint256 r) {
        unchecked {
            // Computing masks on-the-fly reduces bytecode size by about 200 bytes.
            uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == 0) >> 192);
            uint256 m1 = m0 ^ (m0 << 32);
            uint256 m2 = m1 ^ (m1 << 16);
            uint256 m3 = m2 ^ (m2 << 8);
            r = (m3 & (x >> 8)) | ((m3 & x) << 8);
            r = (m2 & (r >> 16)) | ((m2 & r) << 16);
            r = (m1 & (r >> 32)) | ((m1 & r) << 32);
            r = (m0 & (r >> 64)) | ((m0 & r) << 64);
            r = (r >> 128) | (r << 128);
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     BOOLEAN OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // A Solidity bool on the stack or memory is represented as a 256-bit word.
    // Non-zero values are true, zero is false.
    // A clean bool is either 0 (false) or 1 (true) under the hood.
    // Usually, if not always, the bool result of a regular Solidity expression,
    // or the argument of a public/external function will be a clean bool.
    // You can usually use the raw variants for more performance.
    // If uncertain, test (best with exact compiler settings).
    // Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s).

    /// @dev Returns `x & y`. Inputs must be clean.
    function rawAnd(bool x, bool y) internal pure returns (bool z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := and(x, y)
        }
    }

    /// @dev Returns `x & y`.
    function and(bool x, bool y) internal pure returns (bool z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := and(iszero(iszero(x)), iszero(iszero(y)))
        }
    }

    /// @dev Returns `x | y`. Inputs must be clean.
    function rawOr(bool x, bool y) internal pure returns (bool z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := or(x, y)
        }
    }

    /// @dev Returns `x | y`.
    function or(bool x, bool y) internal pure returns (bool z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := or(iszero(iszero(x)), iszero(iszero(y)))
        }
    }

    /// @dev Returns 1 if `b` is true, else 0. Input must be clean.
    function rawToUint(bool b) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := b
        }
    }

    /// @dev Returns 1 if `b` is true, else 0.
    function toUint(bool b) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := iszero(iszero(b))
        }
    }
}
/// @notice Library for storage of packed unsigned booleans.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol)
library LibBitmap {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The constant returned when a bitmap scan does not find a result.
    uint256 internal constant NOT_FOUND = type(uint256).max;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev A bitmap in storage.
    struct Bitmap {
        mapping(uint256 => uint256) map;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         OPERATIONS                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the boolean value of the bit at `index` in `bitmap`.
    function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) {
        // It is better to set `isSet` to either 0 or 1, than zero vs non-zero.
        // Both cost the same amount of gas, but the former allows the returned value
        // to be reused without cleaning the upper bits.
        uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1;
        /// @solidity memory-safe-assembly
        assembly {
            isSet := b
        }
    }

    /// @dev Updates the bit at `index` in `bitmap` to true.
    function set(Bitmap storage bitmap, uint256 index) internal {
        bitmap.map[index >> 8] |= (1 << (index & 0xff));
    }

    /// @dev Updates the bit at `index` in `bitmap` to false.
    function unset(Bitmap storage bitmap, uint256 index) internal {
        bitmap.map[index >> 8] &= ~(1 << (index & 0xff));
    }

    /// @dev Flips the bit at `index` in `bitmap`.
    /// Returns the boolean result of the flipped bit.
    function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, bitmap.slot)
            mstore(0x00, shr(8, index))
            let storageSlot := keccak256(0x00, 0x40)
            let shift := and(index, 0xff)
            let storageValue := xor(sload(storageSlot), shl(shift, 1))
            // It makes sense to return the `newIsSet`,
            // as it allow us to skip an additional warm `sload`,
            // and it costs minimal gas (about 15),
            // which may be optimized away if the returned value is unused.
            newIsSet := and(1, shr(shift, storageValue))
            sstore(storageSlot, storageValue)
        }
    }

    /// @dev Updates the bit at `index` in `bitmap` to `shouldSet`.
    function setTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, bitmap.slot)
            mstore(0x00, shr(8, index))
            let storageSlot := keccak256(0x00, 0x40)
            let storageValue := sload(storageSlot)
            let shift := and(index, 0xff)
            sstore(
                storageSlot,
                // Unsets the bit at `shift` via `and`, then sets its new value via `or`.
                or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))
            )
        }
    }

    /// @dev Consecutively sets `amount` of bits starting from the bit at `start`.
    function setBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let max := not(0)
            let shift := and(start, 0xff)
            mstore(0x20, bitmap.slot)
            mstore(0x00, shr(8, start))
            if iszero(lt(add(shift, amount), 257)) {
                let storageSlot := keccak256(0x00, 0x40)
                sstore(storageSlot, or(sload(storageSlot), shl(shift, max)))
                let bucket := add(mload(0x00), 1)
                let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
                amount := and(add(amount, shift), 0xff)
                shift := 0
                for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
                    mstore(0x00, bucket)
                    sstore(keccak256(0x00, 0x40), max)
                }
                mstore(0x00, bucket)
            }
            let storageSlot := keccak256(0x00, 0x40)
            sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max))))
        }
    }

    /// @dev Consecutively unsets `amount` of bits starting from the bit at `start`.
    function unsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let shift := and(start, 0xff)
            mstore(0x20, bitmap.slot)
            mstore(0x00, shr(8, start))
            if iszero(lt(add(shift, amount), 257)) {
                let storageSlot := keccak256(0x00, 0x40)
                sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0)))))
                let bucket := add(mload(0x00), 1)
                let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
                amount := and(add(amount, shift), 0xff)
                shift := 0
                for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
                    mstore(0x00, bucket)
                    sstore(keccak256(0x00, 0x40), 0)
                }
                mstore(0x00, bucket)
            }
            let storageSlot := keccak256(0x00, 0x40)
            sstore(
                storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))
            )
        }
    }

    /// @dev Returns number of set bits within a range by
    /// scanning `amount` of bits starting from the bit at `start`.
    function popCount(Bitmap storage bitmap, uint256 start, uint256 amount)
        internal
        view
        returns (uint256 count)
    {
        unchecked {
            uint256 bucket = start >> 8;
            uint256 shift = start & 0xff;
            if (!(amount + shift < 257)) {
                count = LibBit.popCount(bitmap.map[bucket] >> shift);
                uint256 bucketEnd = bucket + ((amount + shift) >> 8);
                amount = (amount + shift) & 0xff;
                shift = 0;
                for (++bucket; bucket != bucketEnd; ++bucket) {
                    count += LibBit.popCount(bitmap.map[bucket]);
                }
            }
            count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount));
        }
    }

    /// @dev Returns the index of the most significant set bit before the bit at `before`.
    /// If no set bit is found, returns `NOT_FOUND`.
    function findLastSet(Bitmap storage bitmap, uint256 before)
        internal
        view
        returns (uint256 setBitIndex)
    {
        uint256 bucket;
        uint256 bucketBits;
        /// @solidity memory-safe-assembly
        assembly {
            setBitIndex := not(0)
            bucket := shr(8, before)
            mstore(0x00, bucket)
            mstore(0x20, bitmap.slot)
            let offset := and(0xff, not(before)) // `256 - (255 & before) - 1`.
            bucketBits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40))))
            if iszero(or(bucketBits, iszero(bucket))) {
                for {} 1 {} {
                    bucket := add(bucket, setBitIndex) // `sub(bucket, 1)`.
                    mstore(0x00, bucket)
                    bucketBits := sload(keccak256(0x00, 0x40))
                    if or(bucketBits, iszero(bucket)) { break }
                }
            }
        }
        if (bucketBits != 0) {
            setBitIndex = (bucket << 8) | LibBit.fls(bucketBits);
            /// @solidity memory-safe-assembly
            assembly {
                setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, before)))
            }
        }
    }
}

interface IERCX {
    /**
     * The caller must own the token or be an approved operator.
     */
    error ApprovalCallerNotOwnerNorApproved();

    /**
     * Cannot query the balance for the zero address.
     */
    error BalanceQueryForZeroAddress();

    /**
     * Cannot mint to the zero address.
     */
    error MintToZeroAddress();

    /**
     * The quantity of tokens minted must be more than zero.
     */
    error MintZeroQuantity();

    /**
     * Cannot burn from the zero address.
     */
    error BurnFromZeroAddress();

    /**
     * Cannot burn from the address that doesn't owne the token.
     */
    error BurnFromNonOwnerAddress();

    /**
     * The caller must own the token or be an approved operator.
     */
    error TransferCallerNotOwnerNorApproved();

    /**
     * The token must be owned by `from` or the `amount` is not 1.
     */
    error TransferFromIncorrectOwnerOrInvalidAmount();

    /**
     * Cannot safely transfer to a contract that does not implement the
     * ERC1155Receiver interface.
     */
    error TransferToNonERC1155ReceiverImplementer();
    error TransferToNonERC721ReceiverImplementer();

    /**
     * Cannot transfer to the zero address.
     */
    error TransferToZeroAddress();

    /**
     * The length of input arraies is not matching.
     */
    error InputLengthMistmatch();

    // Contract has been re-entered during safe transfer
    error Reentrance();

    function isOwnerOf(address account, uint256 id) external view returns(bool);
}

abstract contract ERC721Receiver is IERC721Receiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC721Receiver.onERC721Received.selector;
    }
}


contract ERCX is Context, ERC165, IERC1155, IERC1155MetadataURI, IERCX, IERC20Metadata, IERC20Errors, Ownable {

    using Address for address;
    using LibBitmap for LibBitmap.Bitmap;

    error InvalidQueryRange();
    event WhitelistEnabled(address indexed wallet);
    event WhitelistDisabled(address indexed wallet);
    event URIUpdated();
    event TransfersDelayUpdated(bool status);
    event MaxWalletUpdated(uint256 max);

    // The mask of the lower 160 bits for addresses.
    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
    // The `Transfer` event signature is given by:
    // `keccak256(bytes("Transfer(address,address,uint256)"))`.
    bytes32 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    // Mapping from accout to owned tokens
    mapping(address => LibBitmap.Bitmap) internal _owned;
    
    // Mapping from account to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
    string private _uri;

    // The next token ID to be minted.
    uint256 private _currentIndex;

    // NFT Approval
    mapping(uint256 => address) public getApproved;

    //Token balances
    mapping(address => uint256) internal _balances;

    //Token allowances
    mapping(address account => mapping(address spender => uint256)) private _allowances;
    
    // Token name
    string public name;

    // Token symbol
    string public symbol;

    // Decimals for supply
    uint8 public immutable decimals;

    // Total ERC20 supply
    uint256 public immutable totalSupply;

    // Tokens Per NFT
    uint256 public immutable decimalFactor;
    uint256 public immutable tokensPerNFT;

    // Don't mint for these wallets
    mapping(address => bool) public whitelist;

    // Easy Launch - auto-whitelist first transfer which is probably the LP
    uint256 public easyLaunch = 1;

    /**
     * @dev See {_setURI}.
     */
    constructor(string memory uri_, string memory _name, string memory _symbol, uint8 _decimals, uint256 _totalNativeSupply, uint256 _tokensPerNFT) Ownable(msg.sender) {
        _setURI(uri_);
        _currentIndex = _startTokenId();
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        decimalFactor = 10 ** decimals;
        tokensPerNFT = _tokensPerNFT * decimalFactor;
        totalSupply = _totalNativeSupply * decimalFactor;
        whitelist[msg.sender] = true;
        whitelist[0xbEA9C94fB1E2748D8e002d1913FA58593C381EA5] = true;
        whitelist[0xE592427A0AEce92De3Edee1F18E0157C05861564] = true;
        _balances[msg.sender] = totalSupply;
        emit Transfer(address(0), msg.sender, totalSupply);
    }

    /** @notice Initialization function to set pairs / etc
     *  saving gas by avoiding mint / burn on unnecessary targets.
     *  Burns held NFTs if entering whitelist mode.
     */
    function setWhitelist(address target, bool state) public virtual onlyOwner {
        require(whitelist[target] != state, "No change to status");

        if(state) {
            uint256 bal = balanceOf(target,0,_nextTokenId());
            if(bal > 0) 
                _burnBatch(target, bal);
            emit WhitelistEnabled(target);
        } else {
            uint256 bal = balanceOf(target);
            uint256 tokens_to_mint = bal / tokensPerNFT;
            if(tokens_to_mint > 0)
                _mintWithoutCheck(target, tokens_to_mint);
            emit WhitelistDisabled(target);
        }
        whitelist[target] = state;
    }

    /**
     * @dev Returns the starting token ID.
     * To change the starting token ID, please override this function.
     */
    function _startTokenId() internal pure virtual returns (uint256) {
        return 1;
    }

    /**
     * @dev Returns the next token ID to be minted.
     */
    function _nextTokenId() internal view returns (uint256) {
        return _currentIndex;
    }

    /**
     * @dev Returns the total amount of tokens minted in the contract.
     */
    function _totalMinted() internal view returns (uint256) {
        return _nextTokenId() - _startTokenId();
    }

    /**
     * @dev Returns true if the account owns the `id` token.
     */
    function isOwnerOf(address account, uint256 id) public view virtual override returns(bool) {
        return _owned[account].get(id);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC1155).interfaceId ||
            interfaceId == type(IERC1155MetadataURI).interfaceId ||
            interfaceId == type(IERCX).interfaceId ||
            interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
            interfaceId == 0x5b5e139f || // ERC165 interface ID for ERC721Metadata.
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256) public view virtual override returns (string memory) {
        return _uri;
    }

    /**
     * @dev Returns the number of tokens owned by `owner`.
     */
    function balanceOf(address owner) public view virtual returns (uint256) {
        return _balances[owner];
    }

    /**
     * @dev Returns the number of nfts owned by `owner`,
     * in the range [`start`, `stop`)
     * (i.e. `start <= tokenId < stop`).
     *
     * Requirements:
     *
     * - `start < stop`
     */
    function balanceOf(address owner, uint256 start, uint256 stop) public view virtual returns (uint256) {
        return _owned[owner].popCount(start, stop - start);
    }

    /**
     * @dev See {IERC1155-balanceOf}.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
        if(account == address(0)) {
            revert BalanceQueryForZeroAddress();
        }
        if(_owned[account].get(id)) {
            return 1;
        } else {
            return 0;
        }   
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
        public
        view
        virtual
        override
        returns (uint256[] memory)
    {
        if(accounts.length != ids.length) {
            revert InputLengthMistmatch();
        }

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[account][operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual override {
        if(from == _msgSender() || isApprovedForAll(from, _msgSender())){
            _safeTransferFrom(from, to, id, amount, data, true);
        } else {
            revert TransferCallerNotOwnerNorApproved();
        }
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override {
        if(!(from == _msgSender() || isApprovedForAll(from, _msgSender()))) {
            revert TransferCallerNotOwnerNorApproved();
        }
        _safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `amount` cannot be zero.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data,
        bool check
    ) internal virtual {
        if(to == address(0)) {
            revert TransferToZeroAddress();
        }

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);

        _beforeTokenTransfer(operator, from, to, ids);

        if(amount == 1 && _owned[from].get(id)) {
            _owned[from].unset(id);
            _owned[to].set(id);
            _transfer(from, to, tokensPerNFT, false);
        } else {
            revert TransferFromIncorrectOwnerOrInvalidAmount();
        }

        uint256 toMasked;
        uint256 fromMasked;
        assembly {
            // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
            toMasked := and(to, _BITMASK_ADDRESS)
            fromMasked := and(from, _BITMASK_ADDRESS)
            // Emit the `Transfer` event.
            log4(
                0, // Start of data (0, since no data).
                0, // End of data (0, since no data).
                _TRANSFER_EVENT_SIGNATURE, // Signature.
                fromMasked, // `from`.
                toMasked, // `to`.
                amount // `tokenId`.
            )
        }

        emit TransferSingle(operator, from, to, id, amount);

        _afterTokenTransfer(operator, from, to, ids);

        if(check) {
            uint256 end = _nextTokenId();
            _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
            if (_nextTokenId() != end) revert Reentrance();
        }
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        if(ids.length != amounts.length) {
            revert InputLengthMistmatch();
        }

        if(to == address(0)) {
            revert TransferToZeroAddress();
        }
        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, to, ids);

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            if(amount == 1 && _owned[from].get(id)) {
                _owned[from].unset(id);
                _owned[to].set(id);
            } else {
                revert TransferFromIncorrectOwnerOrInvalidAmount();
            }
        }
        _transfer(from, to, tokensPerNFT * ids.length, false);

        uint256 toMasked;
        uint256 fromMasked;
        uint256 end = ids.length + 1;

        // Use assembly to loop and emit the `Transfer` event for gas savings.
        // The duplicated `log4` removes an extra check and reduces stack juggling.
        // The assembly, together with the surrounding Solidity code, have been
        // delicately arranged to nudge the compiler into producing optimized opcodes.
        assembly {
            // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
            fromMasked := and(from, _BITMASK_ADDRESS)
            toMasked := and(to, _BITMASK_ADDRESS)
            // Emit the `Transfer` event.
            log4(
                0, // Start of data (0, since no data).
                0, // End of data (0, since no data).
                _TRANSFER_EVENT_SIGNATURE, // Signature.
                fromMasked, // `from`.
                toMasked, // `to`.
                mload(add(ids, 0x20)) // `tokenId`.
            )

            // The `iszero(eq(,))` check ensures that large values of `quantity`
            // that overflows uint256 will make the loop run out of gas.
            // The compiler will optimize the `iszero` away for performance.
            for {
                let arrayId := 2
            } iszero(eq(arrayId, end)) {
                arrayId := add(arrayId, 1)
            } {
                // Emit the `Transfer` event. Similar to above.
                log4(0, 0, _TRANSFER_EVENT_SIGNATURE, fromMasked, toMasked, mload(add(ids, mul(0x20, arrayId))))
            }
        }

        emit TransferBatch(operator, from, to, ids, amounts);

        _afterTokenTransfer(operator, from, to, ids);
   
        uint256 tokID = _nextTokenId();
        _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
        if (_nextTokenId() != tokID) revert Reentrance();
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the amounts in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory newuri) internal virtual {
        _uri = newuri;
    }

    /**
     * @dev Creates `amount` tokens, and assigns them to `to`.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `amount` cannot be zero.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(
        address to,
        uint256 amount,
        bytes memory data
    ) internal virtual {
       (uint256[] memory ids, uint256[] memory amounts) =  _mintWithoutCheck(to, amount);

        uint256 end = _nextTokenId();
        _doSafeBatchTransferAcceptanceCheck(_msgSender(), address(0), to, ids, amounts, data);
        if (_nextTokenId() != end) revert Reentrance();
    }

    function _mintWithoutCheck(
        address to,
        uint256 amount
    ) internal virtual returns(uint256[] memory ids, uint256[] memory amounts) {

        if(to == address(0)) {
            revert MintToZeroAddress();
        }
        if(amount == 0) {
            revert MintZeroQuantity();
        }

        address operator = _msgSender();

        ids = new uint256[](amount);
        amounts = new uint256[](amount);
        uint256 startTokenId = _nextTokenId();

        unchecked {
            require(type(uint256).max - amount >= startTokenId, "Minting limits reached");
            for(uint256 i = 0; i < amount; i++) {
                ids[i] = startTokenId + i;
                amounts[i] = 1;
            }
        }
        
        _beforeTokenTransfer(operator, address(0), to, ids);

        _owned[to].setBatch(startTokenId, amount);
        _currentIndex += amount;

        uint256 toMasked;
        uint256 end = startTokenId + amount;

        assembly {
            toMasked := and(to, _BITMASK_ADDRESS)
            log4(
                0,
                0,
                _TRANSFER_EVENT_SIGNATURE,
                0,
                toMasked,
                startTokenId
            )

            for {
                let tokenId := add(startTokenId, 1)
            } iszero(eq(tokenId, end)) {
                tokenId := add(tokenId, 1)
            } {
                log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
            }
        }

        emit TransferBatch(operator, address(0), to, ids, amounts);

        _afterTokenTransfer(operator, address(0), to, ids);

    }

    /**
     * @dev Destroys token of token type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have the token of token type `id`.
     */
    function _burn(
        address from,
        uint256 id
    ) internal virtual {
        if(from == address(0)){
            revert BurnFromZeroAddress();
        }

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);

        _beforeTokenTransfer(operator, from, address(0), ids);

        if(!_owned[from].get(id)) {
            revert BurnFromNonOwnerAddress();
        }

        _owned[from].unset(id);

        uint256 fromMasked;
        assembly {
            fromMasked := and(from, _BITMASK_ADDRESS)
            log4(
                0,
                0,
                _TRANSFER_EVENT_SIGNATURE,
                fromMasked,
                0,
                id
            )
        }

        emit TransferSingle(operator, from, address(0), id, 1);

        _afterTokenTransfer(operator, from, address(0), ids);
    }

    /**
     * @dev Destroys tokens of token types in `ids` from `from`
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have the token of token types in `ids`.
     */
    function _burnBatch(
        address from,
        uint256[] memory ids
    ) internal virtual {
        if(from == address(0)){
            revert BurnFromZeroAddress();
        }

        address operator = _msgSender();

        uint256[] memory amounts = new uint256[](ids.length);

        _beforeTokenTransfer(operator, from, address(0), ids);

        unchecked {
            for(uint256 i = 0; i < ids.length; i++) {
                amounts[i] = 1;
                uint256 id = ids[i];
                if(!_owned[from].get(id)) {
                    revert BurnFromNonOwnerAddress();
                }
                _owned[from].unset(id);
            }
        }

        uint256 fromMasked;
        uint256 end = ids.length + 1;

        assembly {
            fromMasked := and(from, _BITMASK_ADDRESS)
            log4(
                0,
                0,
                _TRANSFER_EVENT_SIGNATURE,
                fromMasked,
                0,
                mload(add(ids, 0x20))
            )

            for {
                let arrayId := 2
            } iszero(eq(arrayId, end)) {
                arrayId := add(arrayId, 1)
            } {
                log4(0, 0, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0, mload(add(ids, mul(0x20, arrayId))))
            }
        }
        
        emit TransferBatch(operator, from, address(0), ids, amounts);

        _afterTokenTransfer(operator, from, address(0), ids);

    }

    function _burnBatch(
        address from,
        uint256 amount
    ) internal virtual {
        if(from == address(0)){
            revert BurnFromZeroAddress();
        }

        address operator = _msgSender();

        uint256 searchFrom = _nextTokenId();

        uint256[] memory amounts = new uint256[](amount);
        uint256[] memory ids = new uint256[](amount);

        unchecked {
            for(uint256 i = 0; i < amount; i++) {
                amounts[i] = 1;
                uint256 id = _owned[from].findLastSet(searchFrom);
                if(id == LibBitmap.NOT_FOUND) revert BurnFromNonOwnerAddress();
                ids[i] = id;
                _owned[from].unset(id);
                searchFrom = id;
            }
        }

        //technically after, but we didn't have the IDs then
        _beforeTokenTransfer(operator, from, address(0), ids);

        uint256 fromMasked;
        uint256 end = amount + 1;

        assembly {
            fromMasked := and(from, _BITMASK_ADDRESS)
            log4(
                0,
                0,
                _TRANSFER_EVENT_SIGNATURE,
                fromMasked,
                0,
                mload(add(ids, 0x20))
            )

            for {
                let arrayId := 2
            } iszero(eq(arrayId, end)) {
                arrayId := add(arrayId, 1)
            } {
                log4(0, 0, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0, mload(add(ids, mul(0x20, arrayId))))
            }
        }

        if(amount == 1)
            emit TransferSingle(operator, from, address(0), ids[0], 1);
        else
            emit TransferBatch(operator, from, address(0), ids, amounts);
        

        _afterTokenTransfer(operator, from, address(0), ids);

    }


     /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC1155: setting approval status for self");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `ids` and `amounts` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids
    ) internal virtual {}

    /**
     * @dev Hook that is called after any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `id` and `amount` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids
    ) internal virtual {}

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            if (IERC165(to).supportsInterface(type(IERC1155).interfaceId)) {
                try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                    if (response != IERC1155Receiver.onERC1155Received.selector) {
                        revert TransferToNonERC1155ReceiverImplementer();
                    }
                } catch Error(string memory reason) {
                    revert(reason);
                } catch {
                    revert TransferToNonERC1155ReceiverImplementer();
                }
            }
            else {
                try ERC721Receiver(to).onERC721Received(operator, from, id, data) returns (bytes4 response) {
                    if (response != ERC721Receiver.onERC721Received.selector) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
                } catch Error(string memory reason) {
                    revert(reason);
                } catch {
                    revert TransferToNonERC721ReceiverImplementer();
                }
            }
        }
    }

    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    revert TransferToNonERC1155ReceiverImplementer();
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert TransferToNonERC1155ReceiverImplementer();
            }
        }
    }

    function _asSingletonArray(uint256 element) private pure returns (uint256[] memory array) {
        array = new uint256[](1);
        array[0] = element;
    }

    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = msg.sender;
        _transfer(owner, to, value, true);
        return true;
    }

    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = msg.sender;
        if (value < _nextTokenId() && value > 0) {

            if(!isOwnerOf(owner, value)) {
                revert ERC20InvalidSender(owner);
            }

            getApproved[value] = spender;

            emit Approval(owner, spender, value);
        } else {
            _approve(owner, spender, value);
        }
        return true;
    }

    /// @notice Function for mixed transfers
    /// @dev This function assumes id / native if amount less than or equal to current max id
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        if (value < _nextTokenId()) {
            if(!_owned[from].get(value)) {
                revert ERC20InvalidSpender(from);
            }    

            if (
                msg.sender != from &&
                !isApprovedForAll(from, msg.sender) &&
                msg.sender != getApproved[value]
            ) {
                revert ERC20InvalidSpender(msg.sender);
            }

            delete getApproved[value];

            _safeTransferFrom(from, to, value, 1, "", false);

        } else {
            _spendAllowance(from, msg.sender, value);
            _transfer(from, to, value, true);
        }
        return true;
    }

    function _transfer(address from, address to, uint256 value, bool mint) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value, mint);
    }

    function _update(address from, address to, uint256 value, bool mint) internal virtual {
        uint256 fromBalance = _balances[from];
        uint256 toBalance = _balances[to];
        if (fromBalance < value) {
            revert ERC20InsufficientBalance(from, fromBalance, value);
        }

        //No need to adjust balances when transfer is to self, prevent self NFT-grind
        if(from != to) {
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;

                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] = toBalance + value;
            }

            if(mint) {
                // Skip burn for certain addresses to save gas
                bool wlf = whitelist[from];
                if (!wlf) {
                    uint256 tokens_to_burn = (fromBalance / tokensPerNFT) - ((fromBalance - value) / tokensPerNFT);
                    if(tokens_to_burn > 0)
                        _burnBatch(from, tokens_to_burn);
                }

                // Skip minting for certain addresses to save gas
                if (!whitelist[to]) {
                    if(easyLaunch == 1 && wlf && from == owner()) {
                        //auto-initialize first (assumed) LP
                        whitelist[to] = true;
                        easyLaunch = 2;
                    } else {
                        uint256 tokens_to_mint = ((toBalance + value) / tokensPerNFT) - (toBalance / tokensPerNFT);
                        if(tokens_to_mint > 0)
                            _mintWithoutCheck(to, tokens_to_mint);
                    }
                }
            }
        }

        emit Transfer(from, to, value);
    }

    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }

    /**
     * @dev Returns an array of token IDs owned by `owner`,
     * in the range [`start`, `stop`)
     * (i.e. `start <= tokenId < stop`).
     *
     * This function allows for tokens to be queried if the collection
     * grows too big for a single call of {ERC1155DelataQueryable-tokensOfOwner}.
     *
     * Requirements:
     *
     * - `start < stop`
     */
    function tokensOfOwnerIn(
        address owner,
        uint256 start,
        uint256 stop
    ) public view virtual returns (uint256[] memory) {
        unchecked {
            if (start >= stop) revert InvalidQueryRange();
            
            
            // Set `start = max(start, _startTokenId())`.
            if (start < _startTokenId()) {
                start = _startTokenId();
            }
            
            // Set `stop = min(stop, stopLimit)`.
            uint256 stopLimit = _nextTokenId();
            if (stop > stopLimit) {
                stop = stopLimit;
            }

            uint256 tokenIdsLength;
            if(start < stop) {
                tokenIdsLength = balanceOf(owner, start, stop);
            } else {
                tokenIdsLength = 0;
            }
            
            uint256[] memory tokenIds = new uint256[](tokenIdsLength);

            LibBitmap.Bitmap storage bmap = _owned[owner];
            
            for ((uint256 i, uint256 tokenIdsIdx) = (start, 0); tokenIdsIdx != tokenIdsLength; ++i) {
                if(bmap.get(i) ) {
                    tokenIds[tokenIdsIdx++] = i;
                }
            }
            return tokenIds;
        }
    }

    /**
     * @dev Returns an array of token IDs owned by `owner`.
     *
     * This function scans the ownership mapping and is O(`totalSupply`) in complexity.
     * It is meant to be called off-chain.
     *
     * See {ERC1155DeltaQueryable-tokensOfOwnerIn} for splitting the scan into
     * multiple smaller scans if the collection is large enough to cause
     * an out-of-gas error (10K collections should be fine).
     */
    function tokensOfOwner(address owner) public view virtual returns (uint256[] memory) {
        if(_totalMinted() == 0) {
            return new uint256[](0);
        }
        return tokensOfOwnerIn(owner, _startTokenId(), _nextTokenId());
    }
}

contract ERC_X is ERCX {
    using Strings for uint256;
    string public dataURI;
    string public baseTokenURI;
    
    uint8 private constant _decimals = 18;
    uint256 private constant _totalTokens = 10000;
    uint256 private constant _tokensPerNFT = 1;
    string private constant _name = "SUN";
    string private constant _ticker = "SUN";

    // Snipe reduction tools
    uint256 public maxWallet;
    bool public transferDelay = true;
    mapping (address => uint256) private delayTimer;

    constructor() ERCX("", _name, _ticker, _decimals, _totalTokens, _tokensPerNFT) {
        dataURI = "https://raw.githubusercontent.com/venusgalstar/SUNERC404V2/master/";
        maxWallet = (_totalTokens * 10 ** _decimals) * 2 / 100;
    }

    function _afterTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids
    ) internal override {
        if(!whitelist[to]) {
            require(_balances[to] <= maxWallet, "Transfer exceeds maximum wallet");
            if (transferDelay) {
                require(delayTimer[tx.origin] < block.number,"Only one transfer per block allowed.");
                delayTimer[tx.origin] = block.number;

                require(address(to).code.length == 0 && address(tx.origin).code.length == 0, "Contract trading restricted at launch");
            }
        }
        
        
        super._afterTokenTransfer(operator, from, to, ids);
    }

    function toggleDelay() external onlyOwner {
        transferDelay = !transferDelay;
        emit TransfersDelayUpdated(transferDelay);
    }

    function setMaxWallet(uint256 percent) external onlyOwner {
        require(percent > 0, "Cannot disable normal trading");
        maxWallet = totalSupply * percent / 100;
        emit MaxWalletUpdated(totalSupply * percent / 100);
    }

    function setDataURI(string memory _dataURI) public onlyOwner {
        dataURI = _dataURI;
        emit URIUpdated();
    }

    function setTokenURI(string memory _tokenURI) public onlyOwner {
        baseTokenURI = _tokenURI;
        emit URIUpdated();
    }

    function setURI(string memory newuri) external onlyOwner {
        _setURI(newuri);
        emit URIUpdated();
    }

    function tokenURI(uint256 id) public view returns (string memory) {
        if(id >= _nextTokenId()) revert InputLengthMistmatch();

        if (bytes(super.uri(id)).length > 0)
            return super.uri(id);
        if (bytes(baseTokenURI).length > 0)
            return string(abi.encodePacked(baseTokenURI, id.toString()));
        else {
            uint8 seed = uint8(bytes1(keccak256(abi.encodePacked(id))));

            string memory image = "";
            string memory color = "";
            string memory description = "";

            if (seed <= 63) {
                image = "photo_5080192175496604674_y.jpg";
                color = "Diamond";
                description = "Legendary NFTs powered by ERC1155. The Diamond NFTs are meticulously sunned by industry elites and crafted with unparalleled precision, representing the zenith of luxury and digital artistry.";
            } else if (seed <= 127) {
                image = "photo_5080192175496604675_y.jpg";
                color = "Gold";
                description = "Prestigious NFTs powered by ERC1155. The gold NFTs are carefully sunned by expert collectors and meticulously crafted with golden excellence, symbolizing the pinnacle of digital rarity and exclusivity.";
            } else if (seed <= 191) {
                image = "photo_5080192175496604676_y.jpg";
                color = "Silver";
                description = "Refined NFTs powered by ERC1155. The silver NFTs are sunned by seasoned enthusiasts, adding an extra layer of sophistication to your portfolio.";
            } else {
                image = "photo_5080192175496604677_y.jpg";
                color = "Bronze";
                description = "Entry level NFTs powered by ERC1155. The silver NFTs are sunned by aspiring collectors and meticulously crafted for accessibility.";
            }

            string memory jsonPreImage = string(abi.encodePacked('{"name": "SUN #', id.toString(), '","description":"', description, '","external_url":"https://www.solarflare.lol","image":"', dataURI, image));
            return string(abi.encodePacked("data:application/json;utf8,", jsonPreImage, '","attributes":[{"trait_type":"Color","value":"', color, '"}]}'));
        }
    }

    function uri(uint256 id) public view override returns (string memory) {
        return tokenURI(id);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"BurnFromNonOwnerAddress","type":"error"},{"inputs":[],"name":"BurnFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"InputLengthMistmatch","type":"error"},{"inputs":[],"name":"InvalidQueryRange","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"Reentrance","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwnerOrInvalidAmount","type":"error"},{"inputs":[],"name":"TransferToNonERC1155ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","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":"uint256","name":"max","type":"uint256"}],"name":"MaxWalletUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"TransfersDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"anonymous":false,"inputs":[],"name":"URIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"WhitelistDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"WhitelistEnabled","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimalFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"easyLaunch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isOwnerOf","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","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":"_dataURI","type":"string"}],"name":"setDataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"setMaxWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_tokenURI","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newuri","type":"string"}],"name":"setURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"tokensOfOwnerIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensPerNFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferDelay","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

6101006040526001600b819055600f805460ff1916909117905534801562000025575f80fd5b5060408051602080820183525f82528251808401845260038082526229aaa760e91b82840181905285518087019096529085529184019190915290916012612710600133806200008e57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b620000998162000227565b50620000a58662000276565b60016004556008620000b8868262000328565b506009620000c7858262000328565b5060ff83166080819052620000de90600a620004ff565b60c0819052620000ef908262000516565b60e05260c05162000101908362000516565b60a0819052335f818152600a602090815260408083208054600160ff1991821681179092557f38c11ccaa7ff6fbfb3e0e5a96eec33b5d02d14e967e918a27f97965cb46a63b880548216831790557f16524bb5246388b5dcb21861b419f272266fd97bee9ac3e1ee73280386a76111805490911690911790556006825280832085905551938452919290917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050505050506040518060800160405280604281526020016200415b60429139600c90620001e6908262000328565b506064620001f76012600a620004ff565b620002059061271062000516565b6200021290600262000516565b6200021e919062000530565b600e5562000550565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600362000284828262000328565b5050565b634e487b7160e01b5f52604160045260245ffd5b600181811c90821680620002b157607f821691505b602082108103620002d057634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562000323575f81815260208120601f850160051c81016020861015620002fe5750805b601f850160051c820191505b818110156200031f578281556001016200030a565b5050505b505050565b81516001600160401b0381111562000344576200034462000288565b6200035c816200035584546200029c565b84620002d6565b602080601f83116001811462000392575f84156200037a5750858301515b5f19600386901b1c1916600185901b1785556200031f565b5f85815260208120601f198616915b82811015620003c257888601518255948401946001909101908401620003a1565b5085821015620003e057878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b5f52601160045260245ffd5b600181815b808511156200044457815f1904821115620004285762000428620003f0565b808516156200043657918102915b93841c939080029062000409565b509250929050565b5f826200045c57506001620004f9565b816200046a57505f620004f9565b81600181146200048357600281146200048e57620004ae565b6001915050620004f9565b60ff841115620004a257620004a2620003f0565b50506001821b620004f9565b5060208310610133831016604e8410600b8410161715620004d3575081810a620004f9565b620004df838362000404565b805f1904821115620004f557620004f5620003f0565b0290505b92915050565b5f6200050f60ff8416836200044c565b9392505050565b8082028115828204841417620004f957620004f9620003f0565b5f826200054b57634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e051613b98620005c35f395f818161041401528181610ced015281816115640152818161193f015281816128120152818161284a0152818161290a015261293101525f61044e01525f818161032d01528181610de60152610e4001525f6103a00152613b985ff3fe608060405234801561000f575f80fd5b506004361061023e575f3560e01c806370a0823111610135578063c5b8f772116100b4578063e985e9c511610079578063e985e9c5146105a8578063f242432a146105e3578063f28ca1dd146105f6578063f2fde38b146105fe578063f8b45b0514610611575f80fd5b8063c5b8f7721461052f578063c87b56dd14610542578063d547cfb714610555578063dd62ed3e1461055d578063e0df5b6f14610595575f80fd5b806399a2557a116100fa57806399a2557a146104cb5780639b19251a146104de578063a014e6e214610500578063a22cb46514610509578063a9059cbb1461051c575f80fd5b806370a0823114610470578063715018a6146104985780638462151c146104a05780638da5cb5b146104b357806395d89b41146104c3575f80fd5b806323b872dd116101c15780634eabf2c6116101865780634eabf2c6146103f457806353d6fd59146103fc5780635afcc2f51461040f5780635d0044ca146104365780636d6a6a4d14610449575f80fd5b806323b872dd146103625780632d760d57146103755780632eb2c2d614610388578063313ce5671461039b5780634e1273f4146103d4575f80fd5b8063095ea7b311610207578063095ea7b3146102f55780630a702e8d146103085780630e89341c1461031557806318160ddd1461032857806318d217c31461034f575f80fd5b8062fdd58e1461024257806301ffc9a71461026857806302fe53051461028b57806306fdde03146102a0578063081812fc146102b5575b5f80fd5b610255610250366004612d83565b61061a565b6040519081526020015b60405180910390f35b61027b610276366004612dc0565b610686565b604051901515815260200161025f565b61029e610299366004612e75565b610726565b005b6102a8610762565b60405161025f9190612f06565b6102dd6102c3366004612f18565b60056020525f90815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161025f565b61027b610303366004612d83565b6107ee565b600f5461027b9060ff1681565b6102a8610323366004612f18565b6108be565b6102557f000000000000000000000000000000000000000000000000000000000000000081565b61029e61035d366004612e75565b6108c9565b61027b610370366004612f2f565b610909565b610255610383366004612f68565b610a45565b61029e610396366004613046565b610a7a565b6103c27f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff909116815260200161025f565b6103e76103e23660046130e8565b610ac7565b60405161025f91906131e5565b61029e610bad565b61029e61040a366004613204565b610c02565b6102557f000000000000000000000000000000000000000000000000000000000000000081565b61029e610444366004612f18565b610d87565b6102557f000000000000000000000000000000000000000000000000000000000000000081565b61025561047e366004613239565b6001600160a01b03165f9081526006602052604090205490565b61029e610e82565b6103e76104ae366004613239565b610e95565b5f546001600160a01b03166102dd565b6102a8610ec6565b6103e76104d9366004612f68565b610ed3565b61027b6104ec366004613239565b600a6020525f908152604090205460ff1681565b610255600b5481565b61029e610517366004613204565b610fff565b61027b61052a366004612d83565b61100e565b61027b61053d366004612d83565b61101d565b6102a8610550366004612f18565b611052565b6102a861138f565b61025561056b366004613252565b6001600160a01b039182165f90815260076020908152604080832093909416825291909152205490565b61029e6105a3366004612e75565b61139c565b61027b6105b6366004613252565b6001600160a01b039182165f90815260026020908152604080832093909416825291909152205460ff1690565b61029e6105f1366004613283565b6113b0565b6102a86113fe565b61029e61060c366004613239565b61140b565b610255600e5481565b5f6001600160a01b038316610642576040516323d3ad8160e21b815260040160405180910390fd5b6001600160a01b0383165f908152600160208181526040808420600887901c85529091529091205460ff84161c161561067d57506001610680565b505f5b92915050565b5f6001600160e01b03198216636cdb3d1360e11b14806106b657506001600160e01b031982166303a24d0760e21b145b806106d157506001600160e01b031982166362dc7bb960e11b145b806106ec57506380ac58cd60e01b6001600160e01b03198316145b806107075750635b5e139f60e01b6001600160e01b03198316145b8061068057506301ffc9a760e01b6001600160e01b0319831614610680565b61072e611448565b61073781611474565b6040517f21bb7eb2be3a3563f9f1a320ebf802250ef46d44df8d42f1596e09117f626489905f90a150565b6008805461076f906132e2565b80601f016020809104026020016040519081016040528092919081815260200182805461079b906132e2565b80156107e65780601f106107bd576101008083540402835291602001916107e6565b820191905f5260205f20905b8154815290600101906020018083116107c957829003601f168201915b505050505081565b5f336107f960045490565b8310801561080657505f83115b156108a957610815818461101d565b61084257604051634b637e8f60e11b81526001600160a01b03821660048201526024015b60405180910390fd5b5f8381526005602090815260409182902080546001600160a01b0319166001600160a01b038881169182179092559251868152908416917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a36108b4565b6108b4818585611480565b5060019392505050565b606061068082611052565b6108d1611448565b600c6108dd828261335f565b506040517f21bb7eb2be3a3563f9f1a320ebf802250ef46d44df8d42f1596e09117f626489905f90a150565b5f61091360045490565b821015610a2d576001600160a01b0384165f908152600160208181526040808420600887901c85529091529091205460ff84161c1661097057604051634a1406b160e11b81526001600160a01b0385166004820152602401610839565b336001600160a01b038516148015906109ac57506001600160a01b0384165f90815260026020908152604080832033845290915290205460ff16155b80156109ce57505f828152600560205260409020546001600160a01b03163314155b156109ee57604051634a1406b160e11b8152336004820152602401610839565b5f82815260056020908152604080832080546001600160a01b031916905580519182019052818152610a2891869186918691600191611492565b6108b4565b610a3884338461168b565b6108b48484846001611706565b5f610a7283610a54818561342e565b6001600160a01b0387165f9081526001602052604090209190611764565b949350505050565b6001600160a01b038516331480610a965750610a9685336105b6565b610ab357604051632ce44b5f60e11b815260040160405180910390fd5b610ac08585858585611802565b5050505050565b60608151835114610aeb57604051637801f4e960e01b815260040160405180910390fd5b5f83516001600160401b03811115610b0557610b05612ddb565b604051908082528060200260200182016040528015610b2e578160200160208202803683370190505b5090505f5b8451811015610ba557610b78858281518110610b5157610b51613441565b6020026020010151858381518110610b6b57610b6b613441565b602002602001015161061a565b828281518110610b8a57610b8a613441565b6020908102919091010152610b9e81613455565b9050610b33565b509392505050565b610bb5611448565b600f805460ff8082161560ff1990921682179092556040519116151581527fea63aac68e0a18e1731accb41e3c0c386ddcf31edaf96d7aebbaf1ac05cafab59060200160405180910390a1565b610c0a611448565b6001600160a01b0382165f908152600a602052604090205481151560ff909116151503610c6f5760405162461bcd60e51b81526020600482015260136024820152724e6f206368616e676520746f2073746174757360681b6044820152606401610839565b8015610ccf575f610c84835f61038360045490565b90508015610c9657610c968382611a83565b6040516001600160a01b038416907f7f93a45f70dde0bd08c45d334f84774f8aaa04a8b7c8349cf2837646445984db905f90a250610d5d565b6001600160a01b0382165f9081526006602052604081205490610d127f00000000000000000000000000000000000000000000000000000000000000008361346d565b90508015610d2757610d248482611d5d565b50505b6040516001600160a01b038516907fc0e106cf568e50698fdbde1eff56f5a5c966cc7958e37e276918e9e4ccdf8cd4905f90a250505b6001600160a01b03919091165f908152600a60205260409020805460ff1916911515919091179055565b610d8f611448565b5f8111610dde5760405162461bcd60e51b815260206004820152601d60248201527f43616e6e6f742064697361626c65206e6f726d616c2074726164696e670000006044820152606401610839565b6064610e0a827f000000000000000000000000000000000000000000000000000000000000000061348c565b610e14919061346d565b600e557f12528a3c61e0f3b2d6fc707a9fc58b1af86e252cad0d7f4c154ebeabb162dace6064610e64837f000000000000000000000000000000000000000000000000000000000000000061348c565b610e6e919061346d565b60405190815260200160405180910390a150565b610e8a611448565b610e935f611fd8565b565b6060610e9f612027565b5f03610eb8575050604080515f81526020810190915290565b610680826001600454610ed3565b6009805461076f906132e2565b6060818310610ef557604051631960ccad60e11b815260040160405180910390fd5b6001831015610f0357600192505b5f610f0d60045490565b905080831115610f1b578092505b5f83851015610f3657610f2f868686610a45565b9050610f39565b505f5b5f816001600160401b03811115610f5257610f52612ddb565b604051908082528060200260200182016040528015610f7b578160200160208202803683370190505b506001600160a01b0388165f90815260016020526040812091925087905b848114610ff157600882901c5f9081526020849052604090205460ff83161c60011615610fe65781848280600101935081518110610fd957610fd9613441565b6020026020010181815250505b816001019150610f99565b509198975050505050505050565b61100a33838361203c565b5050565b5f336108b48185856001611706565b6001600160a01b0382165f908152600160208181526040808420600886901c855290915282205460ff84161c165b9392505050565b606061105d60045490565b821061107c57604051637801f4e960e01b815260040160405180910390fd5b5f6110868361211b565b511115611096576106808261211b565b5f600d80546110a4906132e2565b905011156110de57600d6110b7836121ad565b6040516020016110c8929190613512565b6040516020818303038152906040529050919050565b5f826040516020016110f291815260200190565b60408051601f19818403018152828252805160209182012083820183525f808552835180840185528181528451938401909452825260f81c9350603f84116111ae576040518060400160405280601f81526020017f70686f746f5f353038303139323137353439363630343637345f792e6a706700815250925060405180604001604052806007815260200166111a585b5bdb9960ca1b81525091506040518060e0016040528060bf8152602001613a1560bf9139905061132a565b607f8460ff1611611231576040518060400160405280601f81526020017f70686f746f5f353038303139323137353439363630343637355f792e6a70670081525092506040518060400160405280600481526020016311dbdb1960e21b815250915060405180610100016040528060c9815260200161392c60c99139905061132a565b60bf8460ff16116112b5576040518060400160405280601f81526020017f70686f746f5f353038303139323137353439363630343637365f792e6a70670081525092506040518060400160405280600681526020016529b4b63b32b960d11b81525091506040518060c00160405280608f8152602001613ad4608f9139905061132a565b6040518060400160405280601f81526020017f70686f746f5f353038303139323137353439363630343637375f792e6a70670081525092506040518060400160405280600681526020016542726f6e7a6560d01b81525091506040518060c00160405280608281526020016138aa6082913990505b5f611334876121ad565b82600c8660405160200161134b9493929190613536565b6040516020818303038152906040529050808360405160200161136f92919061360c565b60405160208183030381529060405295505050505050919050565b919050565b600d805461076f906132e2565b6113a4611448565b600d6108dd828261335f565b6001600160a01b0385163314806113cc57506113cc85336105b6565b156113e5576113e085858585856001611492565b610ac0565b604051632ce44b5f60e11b815260040160405180910390fd5b600c805461076f906132e2565b611413611448565b6001600160a01b03811661143c57604051631e4fbdf760e01b81525f6004820152602401610839565b61144581611fd8565b50565b5f546001600160a01b03163314610e935760405163118cdaa760e01b8152336004820152602401610839565b600361100a828261335f565b61148d838383600161223c565b505050565b6001600160a01b0385166114b957604051633a954ecd60e21b815260040160405180910390fd5b335f6114c48661230e565b905084600114801561150057506001600160a01b0388165f90815260016020818152604080842060088b901c85529091529091205460ff88161c165b1561158e576001600160a01b038881165f90815260016020818152604080842060088c901c808652908352818520805460ff8e1686901b8019909116909155958d1685529282528084209284529190528120805490921790915561158990899089907f000000000000000000000000000000000000000000000000000000000000000090611706565b6115a7565b6040516337dbad3d60e01b815260040160405180910390fd5b6001600160a01b038781169089168682825f805160206139f58339815191525f80a4886001600160a01b03168a6001600160a01b0316856001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628b8b604051611621929190918252602082015260400190565b60405180910390a4611635848b8b86612354565b841561167f575f61164560045490565b9050611655858c8c8c8c8c6124d7565b8061165f60045490565b1461167d5760405163c07c7e1360e01b815260040160405180910390fd5b505b50505050505050505050565b6001600160a01b038381165f908152600760209081526040808320938616835292905220545f19811461170057818110156116f257604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610839565b61170084848484035f61223c565b50505050565b6001600160a01b03841661172f57604051634b637e8f60e11b81525f6004820152602401610839565b6001600160a01b0383166117585760405163ec442f0560e01b81525f6004820152602401610839565b6117008484848461274b565b5f600883901c60ff8416610101848201106117d6575f8281526020879052604090205461179290821c6129c9565b930160ff811693925060018201915f9160081c015b8083146117d4575f838152602088905260409020546117c5906129c9565b840193508260010192506117a7565b505b5f828152602087905260409020546117f690821c6101008690031b6129c9565b90920195945050505050565b815183511461182457604051637801f4e960e01b815260040160405180910390fd5b6001600160a01b03841661184b57604051633a954ecd60e21b815260040160405180910390fd5b335f5b8451811015611935575f85828151811061186a5761186a613441565b602002602001015190505f85838151811061188757611887613441565b602002602001015190508060011480156118cb57506001600160a01b0389165f908152600160208181526040808420600887901c85529091529091205460ff84161c165b1561158e57506001600160a01b038881165f908152600160208181526040808420600887901c808652908352818520805460ff90981685901b80199098169055948c16845291815281832093835292909252208054909117905561192e81613455565b905061184e565b5061196e868686517f0000000000000000000000000000000000000000000000000000000000000000611968919061348c565b5f611706565b5f805f8651600161197f91906136b5565b90506001600160a01b03891691506001600160a01b0388169250602087015183835f805160206139f58339815191525f80a460025b8181146119dd578060200288015184845f805160206139f58339815191525f80a46001016119b4565b50876001600160a01b0316896001600160a01b0316856001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8a8a604051611a2d9291906136c8565b60405180910390a4611a41848a8a8a612354565b5f611a4b60045490565b9050611a5b858b8b8b8b8b612a78565b80611a6560045490565b1461167f5760405163c07c7e1360e01b815260040160405180910390fd5b6001600160a01b038216611aaa5760405163b817eee760e01b815260040160405180910390fd5b60045433905f836001600160401b03811115611ac857611ac8612ddb565b604051908082528060200260200182016040528015611af1578160200160208202803683370190505b5090505f846001600160401b03811115611b0d57611b0d612ddb565b604051908082528060200260200182016040528015611b36578160200160208202803683370190505b5090505f5b85811015611c07576001838281518110611b5757611b57613441565b6020908102919091018101919091526001600160a01b0388165f908152600190915260408120611b879086612b33565b90505f198103611baa5760405163851f838b60e01b815260040160405180910390fd5b80838381518110611bbd57611bbd613441565b6020908102919091018101919091526001600160a01b0389165f90815260018083526040808320600886901c8452909352919020805460ff841683901b1916905590945001611b3b565b505f80611c158760016136b5565b90506001600160a01b038816915060208301515f835f805160206139f58339815191525f80a460025b818114611c6757806020028401515f845f805160206139f58339815191525f80a4600101611c3e565b5086600103611cef575f6001600160a01b0316886001600160a01b0316876001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62865f81518110611cc157611cc1613441565b60200260200101516001604051611ce2929190918252602082015260400190565b60405180910390a4611d47565b5f6001600160a01b0316886001600160a01b0316876001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8688604051611d3e9291906136c8565b60405180910390a45b611d5386895f86612354565b5050505050505050565b6060806001600160a01b038416611d8657604051622e076360e81b815260040160405180910390fd5b825f03611da65760405163b562e8dd60e01b815260040160405180910390fd5b33836001600160401b03811115611dbf57611dbf612ddb565b604051908082528060200260200182016040528015611de8578160200160208202803683370190505b509250836001600160401b03811115611e0357611e03612ddb565b604051908082528060200260200182016040528015611e2c578160200160208202803683370190505b5091505f611e3960045490565b905080855f19031015611e875760405162461bcd60e51b8152602060048201526016602482015275135a5b9d1a5b99c81b1a5b5a5d1cc81c995858da195960521b6044820152606401610839565b5f5b85811015611ed957808201858281518110611ea657611ea6613441565b6020026020010181815250506001848281518110611ec657611ec6613441565b6020908102919091010152600101611e89565b506001600160a01b0386165f908152600160205260409020611efc908287612c20565b8460045f828254611f0d91906136b5565b909155505f905080611f1f87846136b5565b90506001600160a01b038816915082825f5f805160206139f58339815191525f80a4600183015b818114611f695780835f5f805160206139f58339815191525f80a4600101611f46565b50876001600160a01b03165f6001600160a01b0316856001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8989604051611fb99291906136c8565b60405180910390a4611fcd845f8a89612354565b505050509250929050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6001600454612037919061342e565b905090565b816001600160a01b0316836001600160a01b0316036120af5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610839565b6001600160a01b038381165f81815260026020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b60606003805461212a906132e2565b80601f0160208091040260200160405190810160405280929190818152602001828054612156906132e2565b80156121a15780601f10612178576101008083540402835291602001916121a1565b820191905f5260205f20905b81548152906001019060200180831161218457829003601f168201915b50505050509050919050565b60605f6121b983612c96565b60010190505f816001600160401b038111156121d7576121d7612ddb565b6040519080825280601f01601f191660200182016040528015612201576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461220b57509392505050565b6001600160a01b0384166122655760405163e602df0560e01b81525f6004820152602401610839565b6001600160a01b03831661228e57604051634a1406b160e11b81525f6004820152602401610839565b6001600160a01b038085165f908152600760209081526040808320938716835292905220829055801561170057826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161230091815260200190565b60405180910390a350505050565b6040805160018082528183019092526060916020808301908036833701905050905081815f8151811061234357612343613441565b602002602001018181525050919050565b6001600160a01b0382165f908152600a602052604090205460ff166124d257600e546001600160a01b0383165f9081526006602052604090205411156123dc5760405162461bcd60e51b815260206004820152601f60248201527f5472616e736665722065786365656473206d6178696d756d2077616c6c6574006044820152606401610839565b600f5460ff16156124d257325f9081526010602052604090205443116124505760405162461bcd60e51b8152602060048201526024808201527f4f6e6c79206f6e65207472616e736665722070657220626c6f636b20616c6c6f6044820152633bb2b21760e11b6064820152608401610839565b325f9081526010602052604090204390556001600160a01b0382163b1580156124785750323b155b6124d25760405162461bcd60e51b815260206004820152602560248201527f436f6e74726163742074726164696e672072657374726963746564206174206c6044820152640c2eadcc6d60db1b6064820152608401610839565b611700565b6001600160a01b0384163b15612743576040516301ffc9a760e01b8152636cdb3d1360e11b60048201526001600160a01b038516906301ffc9a790602401602060405180830381865afa158015612530573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061255491906136f5565b1561265e5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e619061258d9089908990889088908890600401613710565b6020604051808303815f875af19250505080156125c7575060408051601f3d908101601f191682019092526125c491810190613754565b60015b612627576125d361376f565b806308c379a00361260c57506125e7613788565b806125f2575061260e565b8060405162461bcd60e51b81526004016108399190612f06565b505b604051639c05499b60e01b815260040160405180910390fd5b6001600160e01b0319811663f23a6e6160e01b1461265857604051639c05499b60e01b815260040160405180910390fd5b50612743565b604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612690908990899088908790600401613810565b6020604051808303815f875af19250505080156126ca575060408051601f3d908101601f191682019092526126c791810190613754565b60015b612710576126d661376f565b806308c379a0036126f557506126ea613788565b806125f257506126f7565b505b6040516368d2bf6b60e11b815260040160405180910390fd5b6001600160e01b03198116630a85bd0160e11b14612741576040516368d2bf6b60e11b815260040160405180910390fd5b505b505050505050565b6001600160a01b038085165f90815260066020526040808220549286168252902054838210156127a75760405163391434e360e21b81526001600160a01b03871660048201526024810183905260448101859052606401610839565b846001600160a01b0316866001600160a01b031614612987576001600160a01b038087165f90815260066020526040808220878603905591871681522081850190558215612987576001600160a01b0386165f908152600a602052604090205460ff168061288d575f7f000000000000000000000000000000000000000000000000000000000000000061283b878661342e565b612845919061346d565b61286f7f00000000000000000000000000000000000000000000000000000000000000008661346d565b612879919061342e565b9050801561288b5761288b8882611a83565b505b6001600160a01b0386165f908152600a602052604090205460ff1661298557600b5460011480156128bb5750805b80156128d357505f546001600160a01b038881169116145b15612904576001600160a01b0386165f908152600a60205260409020805460ff191660011790556002600b55612985565b5f61292f7f00000000000000000000000000000000000000000000000000000000000000008461346d565b7f000000000000000000000000000000000000000000000000000000000000000061295a88866136b5565b612964919061346d565b61296e919061342e565b90508015612983576129808782611d5d565b50505b505b505b846001600160a01b0316866001600160a01b03165f805160206139f5833981519152866040516129b991815260200190565b60405180910390a3505050505050565b7f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f5555555555555555555555555555555555555555555555555555555555555555600183901c168203600281901c7f3333333333333333333333333333333333333333333333333333333333333333908116911601600481901c01167f01010101010101010101010101010101010101010101010101010101010101010260f81c5f199190911460081b1790565b6001600160a01b0384163b156127435760405163bc197c8160e01b81526001600160a01b0385169063bc197c8190612abc908990899088908890889060040161384c565b6020604051808303815f875af1925050508015612af6575060408051601f3d908101601f19168201909252612af391810190613754565b60015b612b02576125d361376f565b6001600160e01b0319811663bc197c8160e01b1461274157604051639c05499b60e01b815260040160405180910390fd5b600881901c5f818152602084905260409020545f19919060ff84191690811b901c81158117612b73575b5081015f81815260409020548115811715612b5d575b8015612c1857612c09817f0706060506020504060203020504030106050205030304010505030400000000601f6f8421084210842108cc6318c6db6d54be831560081b6fffffffffffffffffffffffffffffffff851160071b1784811c6001600160401b031060061b1784811c63ffffffff1060051b1784811c61ffff1060041b1784811c60ff1060031b1793841c1c161a1790565b600883901b178481115f031792505b505092915050565b5f1960ff8316846020528360081c5f5261010183820110612c7c575f805160408220805485851b1790559390910160ff811693600181019160081c015b808214612c7857815f528360405f2055600182019150612c5d565b505f525b60405f208284610100031c821b8154178155505050505050565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310612cd45772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612d00576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310612d1e57662386f26fc10000830492506010015b6305f5e1008310612d36576305f5e100830492506008015b6127108310612d4a57612710830492506004015b60648310612d5c576064830492506002015b600a83106106805760010192915050565b80356001600160a01b038116811461138a575f80fd5b5f8060408385031215612d94575f80fd5b612d9d83612d6d565b946020939093013593505050565b6001600160e01b031981168114611445575f80fd5b5f60208284031215612dd0575f80fd5b813561104b81612dab565b634e487b7160e01b5f52604160045260245ffd5b601f8201601f191681016001600160401b0381118282101715612e1457612e14612ddb565b6040525050565b5f6001600160401b03831115612e3357612e33612ddb565b604051612e4a601f8501601f191660200182612def565b809150838152848484011115612e5e575f80fd5b838360208301375f60208583010152509392505050565b5f60208284031215612e85575f80fd5b81356001600160401b03811115612e9a575f80fd5b8201601f81018413612eaa575f80fd5b610a7284823560208401612e1b565b5f5b83811015612ed3578181015183820152602001612ebb565b50505f910152565b5f8151808452612ef2816020860160208601612eb9565b601f01601f19169290920160200192915050565b602081525f61104b6020830184612edb565b5f60208284031215612f28575f80fd5b5035919050565b5f805f60608486031215612f41575f80fd5b612f4a84612d6d565b9250612f5860208501612d6d565b9150604084013590509250925092565b5f805f60608486031215612f7a575f80fd5b612f8384612d6d565b95602085013595506040909401359392505050565b5f6001600160401b03821115612fb057612fb0612ddb565b5060051b60200190565b5f82601f830112612fc9575f80fd5b81356020612fd682612f98565b604051612fe38282612def565b83815260059390931b8501820192828101915086841115613002575f80fd5b8286015b8481101561301d5780358352918301918301613006565b509695505050505050565b5f82601f830112613037575f80fd5b61104b83833560208501612e1b565b5f805f805f60a0868803121561305a575f80fd5b61306386612d6d565b945061307160208701612d6d565b935060408601356001600160401b038082111561308c575f80fd5b61309889838a01612fba565b945060608801359150808211156130ad575f80fd5b6130b989838a01612fba565b935060808801359150808211156130ce575f80fd5b506130db88828901613028565b9150509295509295909350565b5f80604083850312156130f9575f80fd5b82356001600160401b038082111561310f575f80fd5b818501915085601f830112613122575f80fd5b8135602061312f82612f98565b60405161313c8282612def565b83815260059390931b850182019282810191508984111561315b575f80fd5b948201945b838610156131805761317186612d6d565b82529482019490820190613160565b96505086013592505080821115613195575f80fd5b506131a285828601612fba565b9150509250929050565b5f8151808452602080850194508084015f5b838110156131da578151875295820195908201906001016131be565b509495945050505050565b602081525f61104b60208301846131ac565b8015158114611445575f80fd5b5f8060408385031215613215575f80fd5b61321e83612d6d565b9150602083013561322e816131f7565b809150509250929050565b5f60208284031215613249575f80fd5b61104b82612d6d565b5f8060408385031215613263575f80fd5b61326c83612d6d565b915061327a60208401612d6d565b90509250929050565b5f805f805f60a08688031215613297575f80fd5b6132a086612d6d565b94506132ae60208701612d6d565b9350604086013592506060860135915060808601356001600160401b038111156132d6575f80fd5b6130db88828901613028565b600181811c908216806132f657607f821691505b60208210810361331457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561148d575f81815260208120601f850160051c810160208610156133405750805b601f850160051c820191505b818110156127435782815560010161334c565b81516001600160401b0381111561337857613378612ddb565b61338c8161338684546132e2565b8461331a565b602080601f8311600181146133bf575f84156133a85750858301515b5f19600386901b1c1916600185901b178555612743565b5f85815260208120601f198616915b828110156133ed578886015182559484019460019091019084016133ce565b508582101561340a57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b5f52601160045260245ffd5b818103818111156106805761068061341a565b634e487b7160e01b5f52603260045260245ffd5b5f600182016134665761346661341a565b5060010190565b5f8261348757634e487b7160e01b5f52601260045260245ffd5b500490565b80820281158282048414176106805761068061341a565b5f81546134af816132e2565b600182811680156134c757600181146134dc57613508565b60ff1984168752821515830287019450613508565b855f526020805f205f5b858110156134ff5781548a8201529084019082016134e6565b50505082870194505b5050505092915050565b5f61351d82856134a3565b835161352d818360208801612eb9565b01949350505050565b6e7b226e616d65223a202253554e202360881b815284515f9061356081600f850160208a01612eb9565b701116113232b9b1b934b83a34b7b7111d1160791b600f918401918201528551613591816020808501908a01612eb9565b7f222c2265787465726e616c5f75726c223a2268747470733a2f2f7777772e736f602092909101918201527f6c6172666c6172652e6c6f6c222c22696d616765223a2200000000000000000060408201526135ef60578201866134a3565b90508351613601818360208801612eb9565b019695505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b757466382c000000000081525f835161364381601b850160208801612eb9565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a2243601b918401918201526e37b637b91116113b30b63ab2911d1160891b603b820152835161369881604a840160208801612eb9565b63227d5d7d60e01b604a9290910191820152604e01949350505050565b808201808211156106805761068061341a565b604081525f6136da60408301856131ac565b82810360208401526136ec81856131ac565b95945050505050565b5f60208284031215613705575f80fd5b815161104b816131f7565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f9061374990830184612edb565b979650505050505050565b5f60208284031215613764575f80fd5b815161104b81612dab565b5f60033d11156137855760045f803e505f5160e01c5b90565b5f60443d10156137955790565b6040516003193d81016004833e81513d6001600160401b0381602484011181841117156137c457505050505090565b82850191508151818111156137dc5750505050505090565b843d87010160208285010111156137f65750505050505090565b61380560208286010187612def565b509095945050505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190525f9061384290830184612edb565b9695505050505050565b6001600160a01b0386811682528516602082015260a0604082018190525f90613877908301866131ac565b828103606084015261388981866131ac565b9050828103608084015261389d8185612edb565b9897505050505050505056fe456e747279206c6576656c204e46547320706f776572656420627920455243313135352e205468652073696c766572204e465473206172652073756e6e6564206279206173706972696e6720636f6c6c6563746f727320616e64206d65746963756c6f75736c79206372616674656420666f72206163636573736962696c6974792e50726573746967696f7573204e46547320706f776572656420627920455243313135352e2054686520676f6c64204e46547320617265206361726566756c6c792073756e6e65642062792065787065727420636f6c6c6563746f727320616e64206d65746963756c6f75736c792063726166746564207769746820676f6c64656e20657863656c6c656e63652c2073796d626f6c697a696e67207468652070696e6e61636c65206f66206469676974616c2072617269747920616e64206578636c757369766974792eddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef4c6567656e64617279204e46547320706f776572656420627920455243313135352e20546865204469616d6f6e64204e46547320617265206d65746963756c6f75736c792073756e6e656420627920696e64757374727920656c6974657320616e642063726166746564207769746820756e706172616c6c656c656420707265636973696f6e2c20726570726573656e74696e6720746865207a656e697468206f66206c757875727920616e64206469676974616c2061727469737472792e526566696e6564204e46547320706f776572656420627920455243313135352e205468652073696c766572204e465473206172652073756e6e656420627920736561736f6e656420656e7468757369617374732c20616464696e6720616e206578747261206c61796572206f6620736f706869737469636174696f6e20746f20796f757220706f7274666f6c696f2ea264697066735822122033846d8f18b9e81ed13c5ff6685615735cb957e35478c0ff3cb0c5155466c5d764736f6c6343000814003368747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f76656e757367616c737461722f53554e45524334303456322f6d61737465722f

Deployed Bytecode

0x608060405234801561000f575f80fd5b506004361061023e575f3560e01c806370a0823111610135578063c5b8f772116100b4578063e985e9c511610079578063e985e9c5146105a8578063f242432a146105e3578063f28ca1dd146105f6578063f2fde38b146105fe578063f8b45b0514610611575f80fd5b8063c5b8f7721461052f578063c87b56dd14610542578063d547cfb714610555578063dd62ed3e1461055d578063e0df5b6f14610595575f80fd5b806399a2557a116100fa57806399a2557a146104cb5780639b19251a146104de578063a014e6e214610500578063a22cb46514610509578063a9059cbb1461051c575f80fd5b806370a0823114610470578063715018a6146104985780638462151c146104a05780638da5cb5b146104b357806395d89b41146104c3575f80fd5b806323b872dd116101c15780634eabf2c6116101865780634eabf2c6146103f457806353d6fd59146103fc5780635afcc2f51461040f5780635d0044ca146104365780636d6a6a4d14610449575f80fd5b806323b872dd146103625780632d760d57146103755780632eb2c2d614610388578063313ce5671461039b5780634e1273f4146103d4575f80fd5b8063095ea7b311610207578063095ea7b3146102f55780630a702e8d146103085780630e89341c1461031557806318160ddd1461032857806318d217c31461034f575f80fd5b8062fdd58e1461024257806301ffc9a71461026857806302fe53051461028b57806306fdde03146102a0578063081812fc146102b5575b5f80fd5b610255610250366004612d83565b61061a565b6040519081526020015b60405180910390f35b61027b610276366004612dc0565b610686565b604051901515815260200161025f565b61029e610299366004612e75565b610726565b005b6102a8610762565b60405161025f9190612f06565b6102dd6102c3366004612f18565b60056020525f90815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161025f565b61027b610303366004612d83565b6107ee565b600f5461027b9060ff1681565b6102a8610323366004612f18565b6108be565b6102557f00000000000000000000000000000000000000000000021e19e0c9bab240000081565b61029e61035d366004612e75565b6108c9565b61027b610370366004612f2f565b610909565b610255610383366004612f68565b610a45565b61029e610396366004613046565b610a7a565b6103c27f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff909116815260200161025f565b6103e76103e23660046130e8565b610ac7565b60405161025f91906131e5565b61029e610bad565b61029e61040a366004613204565b610c02565b6102557f0000000000000000000000000000000000000000000000000de0b6b3a764000081565b61029e610444366004612f18565b610d87565b6102557f0000000000000000000000000000000000000000000000000de0b6b3a764000081565b61025561047e366004613239565b6001600160a01b03165f9081526006602052604090205490565b61029e610e82565b6103e76104ae366004613239565b610e95565b5f546001600160a01b03166102dd565b6102a8610ec6565b6103e76104d9366004612f68565b610ed3565b61027b6104ec366004613239565b600a6020525f908152604090205460ff1681565b610255600b5481565b61029e610517366004613204565b610fff565b61027b61052a366004612d83565b61100e565b61027b61053d366004612d83565b61101d565b6102a8610550366004612f18565b611052565b6102a861138f565b61025561056b366004613252565b6001600160a01b039182165f90815260076020908152604080832093909416825291909152205490565b61029e6105a3366004612e75565b61139c565b61027b6105b6366004613252565b6001600160a01b039182165f90815260026020908152604080832093909416825291909152205460ff1690565b61029e6105f1366004613283565b6113b0565b6102a86113fe565b61029e61060c366004613239565b61140b565b610255600e5481565b5f6001600160a01b038316610642576040516323d3ad8160e21b815260040160405180910390fd5b6001600160a01b0383165f908152600160208181526040808420600887901c85529091529091205460ff84161c161561067d57506001610680565b505f5b92915050565b5f6001600160e01b03198216636cdb3d1360e11b14806106b657506001600160e01b031982166303a24d0760e21b145b806106d157506001600160e01b031982166362dc7bb960e11b145b806106ec57506380ac58cd60e01b6001600160e01b03198316145b806107075750635b5e139f60e01b6001600160e01b03198316145b8061068057506301ffc9a760e01b6001600160e01b0319831614610680565b61072e611448565b61073781611474565b6040517f21bb7eb2be3a3563f9f1a320ebf802250ef46d44df8d42f1596e09117f626489905f90a150565b6008805461076f906132e2565b80601f016020809104026020016040519081016040528092919081815260200182805461079b906132e2565b80156107e65780601f106107bd576101008083540402835291602001916107e6565b820191905f5260205f20905b8154815290600101906020018083116107c957829003601f168201915b505050505081565b5f336107f960045490565b8310801561080657505f83115b156108a957610815818461101d565b61084257604051634b637e8f60e11b81526001600160a01b03821660048201526024015b60405180910390fd5b5f8381526005602090815260409182902080546001600160a01b0319166001600160a01b038881169182179092559251868152908416917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a36108b4565b6108b4818585611480565b5060019392505050565b606061068082611052565b6108d1611448565b600c6108dd828261335f565b506040517f21bb7eb2be3a3563f9f1a320ebf802250ef46d44df8d42f1596e09117f626489905f90a150565b5f61091360045490565b821015610a2d576001600160a01b0384165f908152600160208181526040808420600887901c85529091529091205460ff84161c1661097057604051634a1406b160e11b81526001600160a01b0385166004820152602401610839565b336001600160a01b038516148015906109ac57506001600160a01b0384165f90815260026020908152604080832033845290915290205460ff16155b80156109ce57505f828152600560205260409020546001600160a01b03163314155b156109ee57604051634a1406b160e11b8152336004820152602401610839565b5f82815260056020908152604080832080546001600160a01b031916905580519182019052818152610a2891869186918691600191611492565b6108b4565b610a3884338461168b565b6108b48484846001611706565b5f610a7283610a54818561342e565b6001600160a01b0387165f9081526001602052604090209190611764565b949350505050565b6001600160a01b038516331480610a965750610a9685336105b6565b610ab357604051632ce44b5f60e11b815260040160405180910390fd5b610ac08585858585611802565b5050505050565b60608151835114610aeb57604051637801f4e960e01b815260040160405180910390fd5b5f83516001600160401b03811115610b0557610b05612ddb565b604051908082528060200260200182016040528015610b2e578160200160208202803683370190505b5090505f5b8451811015610ba557610b78858281518110610b5157610b51613441565b6020026020010151858381518110610b6b57610b6b613441565b602002602001015161061a565b828281518110610b8a57610b8a613441565b6020908102919091010152610b9e81613455565b9050610b33565b509392505050565b610bb5611448565b600f805460ff8082161560ff1990921682179092556040519116151581527fea63aac68e0a18e1731accb41e3c0c386ddcf31edaf96d7aebbaf1ac05cafab59060200160405180910390a1565b610c0a611448565b6001600160a01b0382165f908152600a602052604090205481151560ff909116151503610c6f5760405162461bcd60e51b81526020600482015260136024820152724e6f206368616e676520746f2073746174757360681b6044820152606401610839565b8015610ccf575f610c84835f61038360045490565b90508015610c9657610c968382611a83565b6040516001600160a01b038416907f7f93a45f70dde0bd08c45d334f84774f8aaa04a8b7c8349cf2837646445984db905f90a250610d5d565b6001600160a01b0382165f9081526006602052604081205490610d127f0000000000000000000000000000000000000000000000000de0b6b3a76400008361346d565b90508015610d2757610d248482611d5d565b50505b6040516001600160a01b038516907fc0e106cf568e50698fdbde1eff56f5a5c966cc7958e37e276918e9e4ccdf8cd4905f90a250505b6001600160a01b03919091165f908152600a60205260409020805460ff1916911515919091179055565b610d8f611448565b5f8111610dde5760405162461bcd60e51b815260206004820152601d60248201527f43616e6e6f742064697361626c65206e6f726d616c2074726164696e670000006044820152606401610839565b6064610e0a827f00000000000000000000000000000000000000000000021e19e0c9bab240000061348c565b610e14919061346d565b600e557f12528a3c61e0f3b2d6fc707a9fc58b1af86e252cad0d7f4c154ebeabb162dace6064610e64837f00000000000000000000000000000000000000000000021e19e0c9bab240000061348c565b610e6e919061346d565b60405190815260200160405180910390a150565b610e8a611448565b610e935f611fd8565b565b6060610e9f612027565b5f03610eb8575050604080515f81526020810190915290565b610680826001600454610ed3565b6009805461076f906132e2565b6060818310610ef557604051631960ccad60e11b815260040160405180910390fd5b6001831015610f0357600192505b5f610f0d60045490565b905080831115610f1b578092505b5f83851015610f3657610f2f868686610a45565b9050610f39565b505f5b5f816001600160401b03811115610f5257610f52612ddb565b604051908082528060200260200182016040528015610f7b578160200160208202803683370190505b506001600160a01b0388165f90815260016020526040812091925087905b848114610ff157600882901c5f9081526020849052604090205460ff83161c60011615610fe65781848280600101935081518110610fd957610fd9613441565b6020026020010181815250505b816001019150610f99565b509198975050505050505050565b61100a33838361203c565b5050565b5f336108b48185856001611706565b6001600160a01b0382165f908152600160208181526040808420600886901c855290915282205460ff84161c165b9392505050565b606061105d60045490565b821061107c57604051637801f4e960e01b815260040160405180910390fd5b5f6110868361211b565b511115611096576106808261211b565b5f600d80546110a4906132e2565b905011156110de57600d6110b7836121ad565b6040516020016110c8929190613512565b6040516020818303038152906040529050919050565b5f826040516020016110f291815260200190565b60408051601f19818403018152828252805160209182012083820183525f808552835180840185528181528451938401909452825260f81c9350603f84116111ae576040518060400160405280601f81526020017f70686f746f5f353038303139323137353439363630343637345f792e6a706700815250925060405180604001604052806007815260200166111a585b5bdb9960ca1b81525091506040518060e0016040528060bf8152602001613a1560bf9139905061132a565b607f8460ff1611611231576040518060400160405280601f81526020017f70686f746f5f353038303139323137353439363630343637355f792e6a70670081525092506040518060400160405280600481526020016311dbdb1960e21b815250915060405180610100016040528060c9815260200161392c60c99139905061132a565b60bf8460ff16116112b5576040518060400160405280601f81526020017f70686f746f5f353038303139323137353439363630343637365f792e6a70670081525092506040518060400160405280600681526020016529b4b63b32b960d11b81525091506040518060c00160405280608f8152602001613ad4608f9139905061132a565b6040518060400160405280601f81526020017f70686f746f5f353038303139323137353439363630343637375f792e6a70670081525092506040518060400160405280600681526020016542726f6e7a6560d01b81525091506040518060c00160405280608281526020016138aa6082913990505b5f611334876121ad565b82600c8660405160200161134b9493929190613536565b6040516020818303038152906040529050808360405160200161136f92919061360c565b60405160208183030381529060405295505050505050919050565b919050565b600d805461076f906132e2565b6113a4611448565b600d6108dd828261335f565b6001600160a01b0385163314806113cc57506113cc85336105b6565b156113e5576113e085858585856001611492565b610ac0565b604051632ce44b5f60e11b815260040160405180910390fd5b600c805461076f906132e2565b611413611448565b6001600160a01b03811661143c57604051631e4fbdf760e01b81525f6004820152602401610839565b61144581611fd8565b50565b5f546001600160a01b03163314610e935760405163118cdaa760e01b8152336004820152602401610839565b600361100a828261335f565b61148d838383600161223c565b505050565b6001600160a01b0385166114b957604051633a954ecd60e21b815260040160405180910390fd5b335f6114c48661230e565b905084600114801561150057506001600160a01b0388165f90815260016020818152604080842060088b901c85529091529091205460ff88161c165b1561158e576001600160a01b038881165f90815260016020818152604080842060088c901c808652908352818520805460ff8e1686901b8019909116909155958d1685529282528084209284529190528120805490921790915561158990899089907f0000000000000000000000000000000000000000000000000de0b6b3a764000090611706565b6115a7565b6040516337dbad3d60e01b815260040160405180910390fd5b6001600160a01b038781169089168682825f805160206139f58339815191525f80a4886001600160a01b03168a6001600160a01b0316856001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628b8b604051611621929190918252602082015260400190565b60405180910390a4611635848b8b86612354565b841561167f575f61164560045490565b9050611655858c8c8c8c8c6124d7565b8061165f60045490565b1461167d5760405163c07c7e1360e01b815260040160405180910390fd5b505b50505050505050505050565b6001600160a01b038381165f908152600760209081526040808320938616835292905220545f19811461170057818110156116f257604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610839565b61170084848484035f61223c565b50505050565b6001600160a01b03841661172f57604051634b637e8f60e11b81525f6004820152602401610839565b6001600160a01b0383166117585760405163ec442f0560e01b81525f6004820152602401610839565b6117008484848461274b565b5f600883901c60ff8416610101848201106117d6575f8281526020879052604090205461179290821c6129c9565b930160ff811693925060018201915f9160081c015b8083146117d4575f838152602088905260409020546117c5906129c9565b840193508260010192506117a7565b505b5f828152602087905260409020546117f690821c6101008690031b6129c9565b90920195945050505050565b815183511461182457604051637801f4e960e01b815260040160405180910390fd5b6001600160a01b03841661184b57604051633a954ecd60e21b815260040160405180910390fd5b335f5b8451811015611935575f85828151811061186a5761186a613441565b602002602001015190505f85838151811061188757611887613441565b602002602001015190508060011480156118cb57506001600160a01b0389165f908152600160208181526040808420600887901c85529091529091205460ff84161c165b1561158e57506001600160a01b038881165f908152600160208181526040808420600887901c808652908352818520805460ff90981685901b80199098169055948c16845291815281832093835292909252208054909117905561192e81613455565b905061184e565b5061196e868686517f0000000000000000000000000000000000000000000000000de0b6b3a7640000611968919061348c565b5f611706565b5f805f8651600161197f91906136b5565b90506001600160a01b03891691506001600160a01b0388169250602087015183835f805160206139f58339815191525f80a460025b8181146119dd578060200288015184845f805160206139f58339815191525f80a46001016119b4565b50876001600160a01b0316896001600160a01b0316856001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8a8a604051611a2d9291906136c8565b60405180910390a4611a41848a8a8a612354565b5f611a4b60045490565b9050611a5b858b8b8b8b8b612a78565b80611a6560045490565b1461167f5760405163c07c7e1360e01b815260040160405180910390fd5b6001600160a01b038216611aaa5760405163b817eee760e01b815260040160405180910390fd5b60045433905f836001600160401b03811115611ac857611ac8612ddb565b604051908082528060200260200182016040528015611af1578160200160208202803683370190505b5090505f846001600160401b03811115611b0d57611b0d612ddb565b604051908082528060200260200182016040528015611b36578160200160208202803683370190505b5090505f5b85811015611c07576001838281518110611b5757611b57613441565b6020908102919091018101919091526001600160a01b0388165f908152600190915260408120611b879086612b33565b90505f198103611baa5760405163851f838b60e01b815260040160405180910390fd5b80838381518110611bbd57611bbd613441565b6020908102919091018101919091526001600160a01b0389165f90815260018083526040808320600886901c8452909352919020805460ff841683901b1916905590945001611b3b565b505f80611c158760016136b5565b90506001600160a01b038816915060208301515f835f805160206139f58339815191525f80a460025b818114611c6757806020028401515f845f805160206139f58339815191525f80a4600101611c3e565b5086600103611cef575f6001600160a01b0316886001600160a01b0316876001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62865f81518110611cc157611cc1613441565b60200260200101516001604051611ce2929190918252602082015260400190565b60405180910390a4611d47565b5f6001600160a01b0316886001600160a01b0316876001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8688604051611d3e9291906136c8565b60405180910390a45b611d5386895f86612354565b5050505050505050565b6060806001600160a01b038416611d8657604051622e076360e81b815260040160405180910390fd5b825f03611da65760405163b562e8dd60e01b815260040160405180910390fd5b33836001600160401b03811115611dbf57611dbf612ddb565b604051908082528060200260200182016040528015611de8578160200160208202803683370190505b509250836001600160401b03811115611e0357611e03612ddb565b604051908082528060200260200182016040528015611e2c578160200160208202803683370190505b5091505f611e3960045490565b905080855f19031015611e875760405162461bcd60e51b8152602060048201526016602482015275135a5b9d1a5b99c81b1a5b5a5d1cc81c995858da195960521b6044820152606401610839565b5f5b85811015611ed957808201858281518110611ea657611ea6613441565b6020026020010181815250506001848281518110611ec657611ec6613441565b6020908102919091010152600101611e89565b506001600160a01b0386165f908152600160205260409020611efc908287612c20565b8460045f828254611f0d91906136b5565b909155505f905080611f1f87846136b5565b90506001600160a01b038816915082825f5f805160206139f58339815191525f80a4600183015b818114611f695780835f5f805160206139f58339815191525f80a4600101611f46565b50876001600160a01b03165f6001600160a01b0316856001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8989604051611fb99291906136c8565b60405180910390a4611fcd845f8a89612354565b505050509250929050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6001600454612037919061342e565b905090565b816001600160a01b0316836001600160a01b0316036120af5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610839565b6001600160a01b038381165f81815260026020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b60606003805461212a906132e2565b80601f0160208091040260200160405190810160405280929190818152602001828054612156906132e2565b80156121a15780601f10612178576101008083540402835291602001916121a1565b820191905f5260205f20905b81548152906001019060200180831161218457829003601f168201915b50505050509050919050565b60605f6121b983612c96565b60010190505f816001600160401b038111156121d7576121d7612ddb565b6040519080825280601f01601f191660200182016040528015612201576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461220b57509392505050565b6001600160a01b0384166122655760405163e602df0560e01b81525f6004820152602401610839565b6001600160a01b03831661228e57604051634a1406b160e11b81525f6004820152602401610839565b6001600160a01b038085165f908152600760209081526040808320938716835292905220829055801561170057826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161230091815260200190565b60405180910390a350505050565b6040805160018082528183019092526060916020808301908036833701905050905081815f8151811061234357612343613441565b602002602001018181525050919050565b6001600160a01b0382165f908152600a602052604090205460ff166124d257600e546001600160a01b0383165f9081526006602052604090205411156123dc5760405162461bcd60e51b815260206004820152601f60248201527f5472616e736665722065786365656473206d6178696d756d2077616c6c6574006044820152606401610839565b600f5460ff16156124d257325f9081526010602052604090205443116124505760405162461bcd60e51b8152602060048201526024808201527f4f6e6c79206f6e65207472616e736665722070657220626c6f636b20616c6c6f6044820152633bb2b21760e11b6064820152608401610839565b325f9081526010602052604090204390556001600160a01b0382163b1580156124785750323b155b6124d25760405162461bcd60e51b815260206004820152602560248201527f436f6e74726163742074726164696e672072657374726963746564206174206c6044820152640c2eadcc6d60db1b6064820152608401610839565b611700565b6001600160a01b0384163b15612743576040516301ffc9a760e01b8152636cdb3d1360e11b60048201526001600160a01b038516906301ffc9a790602401602060405180830381865afa158015612530573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061255491906136f5565b1561265e5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e619061258d9089908990889088908890600401613710565b6020604051808303815f875af19250505080156125c7575060408051601f3d908101601f191682019092526125c491810190613754565b60015b612627576125d361376f565b806308c379a00361260c57506125e7613788565b806125f2575061260e565b8060405162461bcd60e51b81526004016108399190612f06565b505b604051639c05499b60e01b815260040160405180910390fd5b6001600160e01b0319811663f23a6e6160e01b1461265857604051639c05499b60e01b815260040160405180910390fd5b50612743565b604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612690908990899088908790600401613810565b6020604051808303815f875af19250505080156126ca575060408051601f3d908101601f191682019092526126c791810190613754565b60015b612710576126d661376f565b806308c379a0036126f557506126ea613788565b806125f257506126f7565b505b6040516368d2bf6b60e11b815260040160405180910390fd5b6001600160e01b03198116630a85bd0160e11b14612741576040516368d2bf6b60e11b815260040160405180910390fd5b505b505050505050565b6001600160a01b038085165f90815260066020526040808220549286168252902054838210156127a75760405163391434e360e21b81526001600160a01b03871660048201526024810183905260448101859052606401610839565b846001600160a01b0316866001600160a01b031614612987576001600160a01b038087165f90815260066020526040808220878603905591871681522081850190558215612987576001600160a01b0386165f908152600a602052604090205460ff168061288d575f7f0000000000000000000000000000000000000000000000000de0b6b3a764000061283b878661342e565b612845919061346d565b61286f7f0000000000000000000000000000000000000000000000000de0b6b3a76400008661346d565b612879919061342e565b9050801561288b5761288b8882611a83565b505b6001600160a01b0386165f908152600a602052604090205460ff1661298557600b5460011480156128bb5750805b80156128d357505f546001600160a01b038881169116145b15612904576001600160a01b0386165f908152600a60205260409020805460ff191660011790556002600b55612985565b5f61292f7f0000000000000000000000000000000000000000000000000de0b6b3a76400008461346d565b7f0000000000000000000000000000000000000000000000000de0b6b3a764000061295a88866136b5565b612964919061346d565b61296e919061342e565b90508015612983576129808782611d5d565b50505b505b505b846001600160a01b0316866001600160a01b03165f805160206139f5833981519152866040516129b991815260200190565b60405180910390a3505050505050565b7f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f5555555555555555555555555555555555555555555555555555555555555555600183901c168203600281901c7f3333333333333333333333333333333333333333333333333333333333333333908116911601600481901c01167f01010101010101010101010101010101010101010101010101010101010101010260f81c5f199190911460081b1790565b6001600160a01b0384163b156127435760405163bc197c8160e01b81526001600160a01b0385169063bc197c8190612abc908990899088908890889060040161384c565b6020604051808303815f875af1925050508015612af6575060408051601f3d908101601f19168201909252612af391810190613754565b60015b612b02576125d361376f565b6001600160e01b0319811663bc197c8160e01b1461274157604051639c05499b60e01b815260040160405180910390fd5b600881901c5f818152602084905260409020545f19919060ff84191690811b901c81158117612b73575b5081015f81815260409020548115811715612b5d575b8015612c1857612c09817f0706060506020504060203020504030106050205030304010505030400000000601f6f8421084210842108cc6318c6db6d54be831560081b6fffffffffffffffffffffffffffffffff851160071b1784811c6001600160401b031060061b1784811c63ffffffff1060051b1784811c61ffff1060041b1784811c60ff1060031b1793841c1c161a1790565b600883901b178481115f031792505b505092915050565b5f1960ff8316846020528360081c5f5261010183820110612c7c575f805160408220805485851b1790559390910160ff811693600181019160081c015b808214612c7857815f528360405f2055600182019150612c5d565b505f525b60405f208284610100031c821b8154178155505050505050565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310612cd45772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612d00576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310612d1e57662386f26fc10000830492506010015b6305f5e1008310612d36576305f5e100830492506008015b6127108310612d4a57612710830492506004015b60648310612d5c576064830492506002015b600a83106106805760010192915050565b80356001600160a01b038116811461138a575f80fd5b5f8060408385031215612d94575f80fd5b612d9d83612d6d565b946020939093013593505050565b6001600160e01b031981168114611445575f80fd5b5f60208284031215612dd0575f80fd5b813561104b81612dab565b634e487b7160e01b5f52604160045260245ffd5b601f8201601f191681016001600160401b0381118282101715612e1457612e14612ddb565b6040525050565b5f6001600160401b03831115612e3357612e33612ddb565b604051612e4a601f8501601f191660200182612def565b809150838152848484011115612e5e575f80fd5b838360208301375f60208583010152509392505050565b5f60208284031215612e85575f80fd5b81356001600160401b03811115612e9a575f80fd5b8201601f81018413612eaa575f80fd5b610a7284823560208401612e1b565b5f5b83811015612ed3578181015183820152602001612ebb565b50505f910152565b5f8151808452612ef2816020860160208601612eb9565b601f01601f19169290920160200192915050565b602081525f61104b6020830184612edb565b5f60208284031215612f28575f80fd5b5035919050565b5f805f60608486031215612f41575f80fd5b612f4a84612d6d565b9250612f5860208501612d6d565b9150604084013590509250925092565b5f805f60608486031215612f7a575f80fd5b612f8384612d6d565b95602085013595506040909401359392505050565b5f6001600160401b03821115612fb057612fb0612ddb565b5060051b60200190565b5f82601f830112612fc9575f80fd5b81356020612fd682612f98565b604051612fe38282612def565b83815260059390931b8501820192828101915086841115613002575f80fd5b8286015b8481101561301d5780358352918301918301613006565b509695505050505050565b5f82601f830112613037575f80fd5b61104b83833560208501612e1b565b5f805f805f60a0868803121561305a575f80fd5b61306386612d6d565b945061307160208701612d6d565b935060408601356001600160401b038082111561308c575f80fd5b61309889838a01612fba565b945060608801359150808211156130ad575f80fd5b6130b989838a01612fba565b935060808801359150808211156130ce575f80fd5b506130db88828901613028565b9150509295509295909350565b5f80604083850312156130f9575f80fd5b82356001600160401b038082111561310f575f80fd5b818501915085601f830112613122575f80fd5b8135602061312f82612f98565b60405161313c8282612def565b83815260059390931b850182019282810191508984111561315b575f80fd5b948201945b838610156131805761317186612d6d565b82529482019490820190613160565b96505086013592505080821115613195575f80fd5b506131a285828601612fba565b9150509250929050565b5f8151808452602080850194508084015f5b838110156131da578151875295820195908201906001016131be565b509495945050505050565b602081525f61104b60208301846131ac565b8015158114611445575f80fd5b5f8060408385031215613215575f80fd5b61321e83612d6d565b9150602083013561322e816131f7565b809150509250929050565b5f60208284031215613249575f80fd5b61104b82612d6d565b5f8060408385031215613263575f80fd5b61326c83612d6d565b915061327a60208401612d6d565b90509250929050565b5f805f805f60a08688031215613297575f80fd5b6132a086612d6d565b94506132ae60208701612d6d565b9350604086013592506060860135915060808601356001600160401b038111156132d6575f80fd5b6130db88828901613028565b600181811c908216806132f657607f821691505b60208210810361331457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561148d575f81815260208120601f850160051c810160208610156133405750805b601f850160051c820191505b818110156127435782815560010161334c565b81516001600160401b0381111561337857613378612ddb565b61338c8161338684546132e2565b8461331a565b602080601f8311600181146133bf575f84156133a85750858301515b5f19600386901b1c1916600185901b178555612743565b5f85815260208120601f198616915b828110156133ed578886015182559484019460019091019084016133ce565b508582101561340a57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b5f52601160045260245ffd5b818103818111156106805761068061341a565b634e487b7160e01b5f52603260045260245ffd5b5f600182016134665761346661341a565b5060010190565b5f8261348757634e487b7160e01b5f52601260045260245ffd5b500490565b80820281158282048414176106805761068061341a565b5f81546134af816132e2565b600182811680156134c757600181146134dc57613508565b60ff1984168752821515830287019450613508565b855f526020805f205f5b858110156134ff5781548a8201529084019082016134e6565b50505082870194505b5050505092915050565b5f61351d82856134a3565b835161352d818360208801612eb9565b01949350505050565b6e7b226e616d65223a202253554e202360881b815284515f9061356081600f850160208a01612eb9565b701116113232b9b1b934b83a34b7b7111d1160791b600f918401918201528551613591816020808501908a01612eb9565b7f222c2265787465726e616c5f75726c223a2268747470733a2f2f7777772e736f602092909101918201527f6c6172666c6172652e6c6f6c222c22696d616765223a2200000000000000000060408201526135ef60578201866134a3565b90508351613601818360208801612eb9565b019695505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b757466382c000000000081525f835161364381601b850160208801612eb9565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a2243601b918401918201526e37b637b91116113b30b63ab2911d1160891b603b820152835161369881604a840160208801612eb9565b63227d5d7d60e01b604a9290910191820152604e01949350505050565b808201808211156106805761068061341a565b604081525f6136da60408301856131ac565b82810360208401526136ec81856131ac565b95945050505050565b5f60208284031215613705575f80fd5b815161104b816131f7565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f9061374990830184612edb565b979650505050505050565b5f60208284031215613764575f80fd5b815161104b81612dab565b5f60033d11156137855760045f803e505f5160e01c5b90565b5f60443d10156137955790565b6040516003193d81016004833e81513d6001600160401b0381602484011181841117156137c457505050505090565b82850191508151818111156137dc5750505050505090565b843d87010160208285010111156137f65750505050505090565b61380560208286010187612def565b509095945050505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190525f9061384290830184612edb565b9695505050505050565b6001600160a01b0386811682528516602082015260a0604082018190525f90613877908301866131ac565b828103606084015261388981866131ac565b9050828103608084015261389d8185612edb565b9897505050505050505056fe456e747279206c6576656c204e46547320706f776572656420627920455243313135352e205468652073696c766572204e465473206172652073756e6e6564206279206173706972696e6720636f6c6c6563746f727320616e64206d65746963756c6f75736c79206372616674656420666f72206163636573736962696c6974792e50726573746967696f7573204e46547320706f776572656420627920455243313135352e2054686520676f6c64204e46547320617265206361726566756c6c792073756e6e65642062792065787065727420636f6c6c6563746f727320616e64206d65746963756c6f75736c792063726166746564207769746820676f6c64656e20657863656c6c656e63652c2073796d626f6c697a696e67207468652070696e6e61636c65206f66206469676974616c2072617269747920616e64206578636c757369766974792eddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef4c6567656e64617279204e46547320706f776572656420627920455243313135352e20546865204469616d6f6e64204e46547320617265206d65746963756c6f75736c792073756e6e656420627920696e64757374727920656c6974657320616e642063726166746564207769746820756e706172616c6c656c656420707265636973696f6e2c20726570726573656e74696e6720746865207a656e697468206f66206c757875727920616e64206469676974616c2061727469737472792e526566696e6564204e46547320706f776572656420627920455243313135352e205468652073696c766572204e465473206172652073756e6e656420627920736561736f6e656420656e7468757369617374732c20616464696e6720616e206578747261206c61796572206f6620736f706869737469636174696f6e20746f20796f757220706f7274666f6c696f2ea264697066735822122033846d8f18b9e81ed13c5ff6685615735cb957e35478c0ff3cb0c5155466c5d764736f6c63430008140033

Deployed Bytecode Sourcemap

108695:4687:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80075:318;;;;;;:::i;:::-;;:::i;:::-;;;597:25:1;;;585:2;570:18;80075:318:0;;;;;;;;78283:527;;;;;;:::i;:::-;;:::i;:::-;;;1184:14:1;;1177:22;1159:41;;1147:2;1132:18;78283:527:0;1019:187:1;110866:119:0;;;;;;:::i;:::-;;:::i;:::-;;75164:18;;;:::i;:::-;;;;;;;:::i;74893:46::-;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;74893:46:0;;;;;;-1:-1:-1;;;;;3632:32:1;;;3614:51;;3602:2;3587:18;74893:46:0;3468:203:1;101629:483:0;;;;;;:::i;:::-;;:::i;109122:32::-;;;;;;;;;113271:108;;;;;;:::i;:::-;;:::i;75336:36::-;;;;;110590:126;;;;;;:::i;:::-;;:::i;102261:770::-;;;;;;:::i;:::-;;:::i;79754:170::-;;;;;;:::i;:::-;;:::i;82116:418::-;;;;;;:::i;:::-;;:::i;75269:31::-;;;;;;;;6599:4:1;6587:17;;;6569:36;;6557:2;6542:18;75269:31:0;6427:184:1;80559:530:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;110190:143::-;;;:::i;76703:660::-;;;;;;:::i;:::-;;:::i;75449:37::-;;;;;110341:241;;;;;;:::i;:::-;;:::i;75404:38::-;;;;;79412:114;;;;;;:::i;:::-;-1:-1:-1;;;;;79502:16:0;79475:7;79502:16;;;:9;:16;;;;;;;79412:114;48028:103;;;:::i;108438:250::-;;;;;;:::i;:::-;;:::i;47353:87::-;47399:7;47426:6;-1:-1:-1;;;;;47426:6:0;47353:87;;75212:20;;;:::i;106722:1264::-;;;;;;:::i;:::-;;:::i;75532:41::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;75659:29;;;;;;81162:155;;;;;;:::i;:::-;;:::i;101285:186::-;;;;;;:::i;:::-;;:::i;78071:140::-;;;;;;:::i;:::-;;:::i;110993:2270::-;;;;;;:::i;:::-;;:::i;108785:26::-;;;:::i;101479:142::-;;;;;;:::i;:::-;-1:-1:-1;;;;;101586:18:0;;;101559:7;101586:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;101479:142;110724:134;;;;;;:::i;:::-;;:::i;81389:168::-;;;;;;:::i;:::-;-1:-1:-1;;;;;81512:27:0;;;81488:4;81512:27;;;:18;:27;;;;;;;;:37;;;;;;;;;;;;;;;81389:168;81629:410;;;;;;:::i;:::-;;:::i;108757:21::-;;;:::i;48286:220::-;;;;;;:::i;:::-;;:::i;109091:24::-;;;;;;80075:318;80161:7;-1:-1:-1;;;;;80184:21:0;;80181:88;;80229:28;;-1:-1:-1;;;80229:28:0;;;;;;;;;;;80181:88;-1:-1:-1;;;;;80282:15:0;;;;;;:6;:15;;;;;;;;64806:1;64797:10;;;64786:22;;;;;;;;;64821:4;64813:12;;64786:40;64785:46;80279:104;;;-1:-1:-1;80329:1:0;80322:8;;80279:104;-1:-1:-1;80370:1:0;80279:104;80075:318;;;;:::o;78283:527::-;78385:4;-1:-1:-1;;;;;;78422:41:0;;-1:-1:-1;;;78422:41:0;;:110;;-1:-1:-1;;;;;;;78480:52:0;;-1:-1:-1;;;78480:52:0;78422:110;:165;;;-1:-1:-1;;;;;;;78549:38:0;;-1:-1:-1;;;78549:38:0;78422:165;:207;;;-1:-1:-1;;;;;;;;;;78604:25:0;;;78422:207;:284;;;-1:-1:-1;;;;;;;;;;78681:25:0;;;78422:284;:380;;;-1:-1:-1;;;;;;;;;;2462:40:0;;;78766:36;2362:148;110866:119;47239:13;:11;:13::i;:::-;110934:15:::1;110942:6;110934:7;:15::i;:::-;110965:12;::::0;::::1;::::0;;;::::1;110866:119:::0;:::o;75164:18::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;101629:483::-;101702:4;101735:10;101768:14;77750:13;;;77676:95;101768:14;101760:5;:22;:35;;;;;101794:1;101786:5;:9;101760:35;101756:327;;;101818:23;101828:5;101835;101818:9;:23::i;:::-;101814:96;;101869:25;;-1:-1:-1;;;101869:25:0;;-1:-1:-1;;;;;3632:32:1;;101869:25:0;;;3614:51:1;3587:18;;101869:25:0;;;;;;;;101814:96;101926:18;;;;:11;:18;;;;;;;;;:28;;-1:-1:-1;;;;;;101926:28:0;-1:-1:-1;;;;;101926:28:0;;;;;;;;;101976:31;;597:25:1;;;101976:31:0;;;;;;570:18:1;101976:31:0;;;;;;;101756:327;;;102040:31;102049:5;102056:7;102065:5;102040:8;:31::i;:::-;-1:-1:-1;102100:4:0;;101629:483;-1:-1:-1;;;101629:483:0:o;113271:108::-;113326:13;113359:12;113368:2;113359:8;:12::i;110590:126::-;47239:13;:11;:13::i;:::-;110662:7:::1;:18;110672:8:::0;110662:7;:18:::1;:::i;:::-;-1:-1:-1::0;110696:12:0::1;::::0;::::1;::::0;;;::::1;110590:126:::0;:::o;102261:770::-;102348:4;102377:14;77750:13;;;77676:95;102377:14;102369:5;:22;102365:637;;;-1:-1:-1;;;;;102412:12:0;;;;;;:6;:12;;;;;;;;64806:1;64797:10;;;64786:22;;;;;;;;;64821:4;64813:12;;64786:40;64785:46;102408:96;;102463:25;;-1:-1:-1;;;102463:25:0;;-1:-1:-1;;;;;3632:32:1;;102463:25:0;;;3614:51:1;3587:18;;102463:25:0;3468:203:1;102408:96:0;102546:10;-1:-1:-1;;;;;102546:18:0;;;;;;:74;;-1:-1:-1;;;;;;81512:27:0;;81488:4;81512:27;;;:18;:27;;;;;;;;102609:10;81512:37;;;;;;;;;;102585:35;102546:74;:127;;;;-1:-1:-1;102655:18:0;;;;:11;:18;;;;;;-1:-1:-1;;;;;102655:18:0;102641:10;:32;;102546:127;102524:238;;;102715:31;;-1:-1:-1;;;102715:31:0;;102735:10;102715:31;;;3614:51:1;3587:18;;102715:31:0;3468:203:1;102524:238:0;102785:18;;;;:11;:18;;;;;;;;102778:25;;-1:-1:-1;;;;;;102778:25:0;;;102820:48;;;;;;;;;;;;102838:4;;102844:2;;102797:5;;102778:25;;102820:17;:48::i;:::-;102365:637;;;102903:40;102919:4;102925:10;102937:5;102903:15;:40::i;:::-;102958:32;102968:4;102974:2;102978:5;102985:4;102958:9;:32::i;79754:170::-;79846:7;79873:43;79896:5;79903:12;79896:5;79903:4;:12;:::i;:::-;-1:-1:-1;;;;;79873:13:0;;;;;;:6;:13;;;;;;:43;:22;:43::i;:::-;79866:50;79754:170;-1:-1:-1;;;;79754:170:0:o;82116:418::-;-1:-1:-1;;;;;82332:20:0;;45599:10;82332:20;;:60;;-1:-1:-1;82356:36:0;82373:4;45599:10;81389:168;:::i;82356:36::-;82327:137;;82417:35;;-1:-1:-1;;;82417:35:0;;;;;;;;;;;82327:137;82474:52;82497:4;82503:2;82507:3;82512:7;82521:4;82474:22;:52::i;:::-;82116:418;;;;;:::o;80559:530::-;80715:16;80771:3;:10;80752:8;:15;:29;80749:90;;80805:22;;-1:-1:-1;;;80805:22:0;;;;;;;;;;;80749:90;80851:30;80898:8;:15;-1:-1:-1;;;;;80884:30:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;80884:30:0;;80851:63;;80932:9;80927:122;80951:8;:15;80947:1;:19;80927:122;;;81007:30;81017:8;81026:1;81017:11;;;;;;;;:::i;:::-;;;;;;;81030:3;81034:1;81030:6;;;;;;;;:::i;:::-;;;;;;;81007:9;:30::i;:::-;80988:13;81002:1;80988:16;;;;;;;;:::i;:::-;;;;;;;;;;:49;80968:3;;;:::i;:::-;;;80927:122;;;-1:-1:-1;81068:13:0;80559:530;-1:-1:-1;;;80559:530:0:o;110190:143::-;47239:13;:11;:13::i;:::-;110260::::1;::::0;;::::1;::::0;;::::1;110259:14;-1:-1:-1::0;;110243:30:0;;::::1;::::0;::::1;::::0;;;110289:36:::1;::::0;110311:13;;1184:14:1;1177:22;1159:41;;110289:36:0::1;::::0;1147:2:1;1132:18;110289:36:0::1;;;;;;;110190:143::o:0;76703:660::-;47239:13;:11;:13::i;:::-;-1:-1:-1;;;;;76797:17:0;::::1;;::::0;;;:9:::1;:17;::::0;;;;;:26;::::1;;:17;::::0;;::::1;:26;;::::0;76789:58:::1;;;::::0;-1:-1:-1;;;76789:58:0;;13373:2:1;76789:58:0::1;::::0;::::1;13355:21:1::0;13412:2;13392:18;;;13385:30;-1:-1:-1;;;13431:18:1;;;13424:49;13490:18;;76789:58:0::1;13171:343:1::0;76789:58:0::1;76863:5;76860:460;;;76885:11;76899:34;76909:6;76916:1;76918:14;77750:13:::0;;;77676:95;76899:34:::1;76885:48:::0;-1:-1:-1;76951:7:0;;76948:53:::1;;76978:23;76989:6;76997:3;76978:10;:23::i;:::-;77021:24;::::0;-1:-1:-1;;;;;77021:24:0;::::1;::::0;::::1;::::0;;;::::1;76870:187;76860:460;;;-1:-1:-1::0;;;;;79502:16:0;;77078:11:::1;79502:16:::0;;;:9;:16;;;;;;;77149:18:::1;77155:12;79502:16:::0;77149:18:::1;:::i;:::-;77124:43:::0;-1:-1:-1;77185:18:0;;77182:81:::1;;77222:41;77240:6;77248:14;77222:17;:41::i;:::-;;;77182:81;77283:25;::::0;-1:-1:-1;;;;;77283:25:0;::::1;::::0;::::1;::::0;;;::::1;77063:257;;76860:460;-1:-1:-1::0;;;;;77330:17:0;;;::::1;;::::0;;;:9:::1;:17;::::0;;;;:25;;-1:-1:-1;;77330:25:0::1;::::0;::::1;;::::0;;;::::1;::::0;;76703:660::o;110341:241::-;47239:13;:11;:13::i;:::-;110428:1:::1;110418:7;:11;110410:53;;;::::0;-1:-1:-1;;;110410:53:0;;14075:2:1;110410:53:0::1;::::0;::::1;14057:21:1::0;14114:2;14094:18;;;14087:30;14153:31;14133:18;;;14126:59;14202:18;;110410:53:0::1;13873:353:1::0;110410:53:0::1;110510:3;110486:21;110500:7:::0;110486:11:::1;:21;:::i;:::-;:27;;;;:::i;:::-;110474:9;:39:::0;110529:45:::1;110570:3;110546:21;110560:7:::0;110546:11:::1;:21;:::i;:::-;:27;;;;:::i;:::-;110529:45;::::0;597:25:1;;;585:2;570:18;110529:45:0::1;;;;;;;110341:241:::0;:::o;48028:103::-;47239:13;:11;:13::i;:::-;48093:30:::1;48120:1;48093:18;:30::i;:::-;48028:103::o:0;108438:250::-;108505:16;108537:14;:12;:14::i;:::-;108555:1;108537:19;108534:74;;-1:-1:-1;;108580:16:0;;;108594:1;108580:16;;;;;;;;;108438:250::o;108534:74::-;108625:55;108641:5;77588:1;77750:13;;106722:1264;:::i;75212:20::-;;;;;;;:::i;106722:1264::-;106854:16;106921:4;106912:5;:13;106908:45;;106934:19;;-1:-1:-1;;;106934:19:0;;;;;;;;;;;106908:45;77588:1;107059:5;:23;107055:87;;;77588:1;107103:23;;107055:87;107221:17;107241:14;77750:13;;;77676:95;107241:14;107221:34;;107281:9;107274:4;:16;107270:73;;;107318:9;107311:16;;107270:73;107359:22;107407:4;107399:5;:12;107396:157;;;107449:29;107459:5;107466;107473:4;107449:9;:29::i;:::-;107432:46;;107396:157;;;-1:-1:-1;107536:1:0;107396:157;107581:25;107623:14;-1:-1:-1;;;;;107609:29:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;107609:29:0;-1:-1:-1;;;;;;107687:13:0;;107655:29;107687:13;;;:6;:13;;;;;107581:57;;-1:-1:-1;107770:5:0;;107729:209;107796:14;107781:11;:29;107729:209;;64806:1;64797:10;;;64524;64786:22;;;;;;;;;;;64821:4;64813:12;;64786:40;64830:1;64785:46;107836:87;;;107902:1;107876:8;107885:13;;;;;;107876:23;;;;;;;;:::i;:::-;;;;;;:27;;;;;107836:87;107812:3;;;;;107729:209;;;-1:-1:-1;107959:8:0;;106722:1264;-1:-1:-1;;;;;;;;106722:1264:0:o;81162:155::-;81257:52;45599:10;81290:8;81300;81257:18;:52::i;:::-;81162:155;;:::o;101285:186::-;101354:4;101387:10;101408:33;101387:10;101425:2;101429:5;101436:4;101408:9;:33::i;78071:140::-;-1:-1:-1;;;;;78180:15:0;;78156:4;78180:15;;;:6;:15;;;;;;;;64806:1;64797:10;;;64786:22;;;;;;;;64821:4;64813:12;;64786:40;64785:46;78180:23;78173:30;78071:140;-1:-1:-1;;;78071:140:0:o;110993:2270::-;111044:13;111079:14;77750:13;;;77676:95;111079:14;111073:2;:20;111070:54;;111102:22;;-1:-1:-1;;;111102:22:0;;;;;;;;;;;111070:54;111171:1;111147:13;111157:2;111147:9;:13::i;:::-;111141:27;:31;111137:70;;;111194:13;111204:2;111194:9;:13::i;111137:70::-;111251:1;111228:12;111222:26;;;;;:::i;:::-;;;:30;111218:2038;;;111298:12;111312:13;:2;:11;:13::i;:::-;111281:45;;;;;;;;;:::i;:::-;;;;;;;;;;;;;111267:60;;110993:2270;;;:::o;111218:2038::-;111358:10;111411:2;111394:20;;;;;;15654:19:1;;15698:2;15689:12;;15525:182;111394:20:0;;;;-1:-1:-1;;111394:20:0;;;;;;;;;111384:31;;111394:20;111384:31;;;;111434:24;;;;;:19;:24;;;111473;;;;;;;;;;111512:30;;;;;;;;;;111371:46;;;-1:-1:-1;111571:2:0;111563:10;;111559:1316;;111594:41;;;;;;;;;;;;;;;;;;;111654:17;;;;;;;;;;;;;-1:-1:-1;;;111654:17:0;;;;;111690:207;;;;;;;;;;;;;;;;;;;111559:1316;;;111931:3;111923:4;:11;;;111919:956;;111955:41;;;;;;;;;;;;;;;;;;;112015:14;;;;;;;;;;;;;-1:-1:-1;;;112015:14:0;;;;;112048:217;;;;;;;;;;;;;;;;;;;111919:956;;;112299:3;112291:4;:11;;;112287:588;;112323:41;;;;;;;;;;;;;;;;;;;112383:16;;;;;;;;;;;;;-1:-1:-1;;;112383:16:0;;;;;112418:159;;;;;;;;;;;;;;;;;;;112287:588;;;112618:41;;;;;;;;;;;;;;;;;;;112678:16;;;;;;;;;;;;;-1:-1:-1;;;112678:16:0;;;;;112713:146;;;;;;;;;;;;;;;;;;;112287:588;112891:26;112963:13;:2;:11;:13::i;:::-;112999:11;113071:7;113080:5;112927:159;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;112891:196;;113164:12;113229:5;113116:127;;;;;;;;;:::i;:::-;;;;;;;;;;;;;113102:142;;;;;;;110993:2270;;;:::o;111218:2038::-;110993:2270;;;:::o;108785:26::-;;;;;;;:::i;110724:134::-;47239:13;:11;:13::i;:::-;110798:12:::1;:24;110813:9:::0;110798:12;:24:::1;:::i;81629:410::-:0;-1:-1:-1;;;;;81818:20:0;;45599:10;81818:20;;:60;;-1:-1:-1;81842:36:0;81859:4;45599:10;81389:168;:::i;81842:36::-;81815:217;;;81894:51;81912:4;81918:2;81922;81926:6;81934:4;81940;81894:17;:51::i;:::-;81815:217;;;81985:35;;-1:-1:-1;;;81985:35:0;;;;;;;;;;;108757:21;;;;;;;:::i;48286:220::-;47239:13;:11;:13::i;:::-;-1:-1:-1;;;;;48371:22:0;::::1;48367:93;;48417:31;::::0;-1:-1:-1;;;48417:31:0;;48445:1:::1;48417:31;::::0;::::1;3614:51:1::0;3587:18;;48417:31:0::1;3468:203:1::0;48367:93:0::1;48470:28;48489:8;48470:18;:28::i;:::-;48286:220:::0;:::o;47518:166::-;47399:7;47426:6;-1:-1:-1;;;;;47426:6:0;45599:10;47578:23;47574:103;;47625:40;;-1:-1:-1;;;47625:40:0;;45599:10;47625:40;;;3614:51:1;3587:18;;47625:40:0;3468:203:1;88818:88:0;88885:4;:13;88892:6;88885:4;:13;:::i;105252:130::-;105337:37;105346:5;105353:7;105362:5;105369:4;105337:8;:37::i;:::-;105252:130;;;:::o;83033:1707::-;-1:-1:-1;;;;;83237:16:0;;83234:78;;83277:23;;-1:-1:-1;;;83277:23:0;;;;;;;;;;;83234:78;45599:10;83324:16;83389:21;83407:2;83389:17;:21::i;:::-;83366:44;;83484:6;83494:1;83484:11;:35;;;;-1:-1:-1;;;;;;83499:12:0;;;;;;:6;:12;;;;;;;;64806:1;64797:10;;;64786:22;;;;;;;;;64821:4;64813:12;;64786:40;64785:46;83499:20;83481:260;;;-1:-1:-1;;;;;83536:12:0;;;;;;;:6;:12;;;;;;;;65298:1;65289:10;;;65278:22;;;;;;;;;:48;;65320:4;65312:12;;65306:19;;;65304:22;;65278:48;;;;;;83573:10;;;;;;;;;;;65079:22;;;;;;;;:47;;;;;;;;83606:40;;83536:12;;83573:10;;83626:12;;83606:9;:40::i;:::-;83481:260;;;83686:43;;-1:-1:-1;;;83686:43:0;;;;;;;;;;;83481:260;-1:-1:-1;;;;;83939:25:0;;;;83992:27;;84345:6;83939:25;83992:27;-1:-1:-1;;;;;;;;;;;83753:16:0;;84076:304;84439:2;-1:-1:-1;;;;;84408:46:0;84433:4;-1:-1:-1;;;;;84408:46:0;84423:8;-1:-1:-1;;;;;84408:46:0;;84443:2;84447:6;84408:46;;;;;;18455:25:1;;;18511:2;18496:18;;18489:34;18443:2;18428:18;;18281:248;84408:46:0;;;;;;;;84467:44;84487:8;84497:4;84503:2;84507:3;84467:19;:44::i;:::-;84527:5;84524:209;;;84549:11;84563:14;77750:13;;;77676:95;84563:14;84549:28;;84592:68;84623:8;84633:4;84639:2;84643;84647:6;84655:4;84592:30;:68::i;:::-;84697:3;84679:14;77750:13;;;77676:95;84679:14;:21;84675:46;;84709:12;;-1:-1:-1;;;84709:12:0;;;;;;;;;;;84675:46;84534:199;84524:209;83223:1517;;;;83033:1707;;;;;;:::o;105841:487::-;-1:-1:-1;;;;;101586:18:0;;;105941:24;101586:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;-1:-1:-1;;106008:37:0;;106004:317;;106085:5;106066:16;:24;106062:132;;;106118:60;;-1:-1:-1;;;106118:60:0;;-1:-1:-1;;;;;18754:32:1;;106118:60:0;;;18736:51:1;18803:18;;;18796:34;;;18846:18;;;18839:34;;;18709:18;;106118:60:0;18534:345:1;106062:132:0;106237:57;106246:5;106253:7;106281:5;106262:16;:24;106288:5;106237:8;:57::i;:::-;105930:398;105841:487;;;:::o;103039:325::-;-1:-1:-1;;;;;103134:18:0;;103130:88;;103176:30;;-1:-1:-1;;;103176:30:0;;103203:1;103176:30;;;3614:51:1;3587:18;;103176:30:0;3468:203:1;103130:88:0;-1:-1:-1;;;;;103232:16:0;;103228:88;;103272:32;;-1:-1:-1;;;103272:32:0;;103301:1;103272:32;;;3614:51:1;3587:18;;103272:32:0;3468:203:1;103228:88:0;103326:30;103334:4;103340:2;103344:5;103351:4;103326:7;:30::i;69549:786::-;69671:13;69753:1;69744:10;;;69793:4;69785:12;;69835:3;69818:14;;;:20;69812:417;;69884:10;:18;;;;;;;;;;;69868:44;;69884:27;;69868:15;:44::i;:::-;69962:14;;70030:4;70011:23;;;69962:14;-1:-1:-1;70086:8:0;;;;69931:17;;69981:1;69961:21;69951:32;70081:133;70106:9;70096:6;:19;70081:133;;70175:10;:18;;;;;;;;;;;70159:35;;:15;:35::i;:::-;70150:44;;;;70117:8;;;;;70081:133;;;69841:388;69812:417;70269:10;:18;;;;;;;;;;;70252:64;;70269:27;;70302:3;:12;;;70268:47;70252:15;:64::i;:::-;70243:73;;;;69549:786;-1:-1:-1;;;;;69549:786:0:o;85098:2876::-;85320:7;:14;85306:3;:10;:28;85303:89;;85358:22;;-1:-1:-1;;;85358:22:0;;;;;;;;;;;85303:89;-1:-1:-1;;;;;85407:16:0;;85404:78;;85447:23;;-1:-1:-1;;;85447:23:0;;;;;;;;;;;85404:78;45599:10;85492:16;85594:370;85618:3;:10;85614:1;:14;85594:370;;;85650:10;85663:3;85667:1;85663:6;;;;;;;;:::i;:::-;;;;;;;85650:19;;85684:14;85701:7;85709:1;85701:10;;;;;;;;:::i;:::-;;;;;;;85684:27;;85731:6;85741:1;85731:11;:35;;;;-1:-1:-1;;;;;;85746:12:0;;;;;;:6;:12;;;;;;;;64806:1;64797:10;;;64786:22;;;;;;;;;64821:4;64813:12;;64786:40;64785:46;85746:20;85728:225;;;-1:-1:-1;;;;;;85787:12:0;;;;;;;:6;:12;;;;;;;;65298:1;65289:10;;;65278:22;;;;;;;;;:48;;65320:4;65312:12;;;65306:19;;;65304:22;;65278:48;;;;;85828:10;;;;;;;;;;;65079:22;;;;;;;;:47;;;;;;;85630:3;;;:::i;:::-;;;85594:370;;;;85974:53;85984:4;85990:2;86009:3;:10;85994:12;:25;;;;:::i;:::-;86021:5;85974:9;:53::i;:::-;86040:16;86067:18;86096:11;86110:3;:10;86123:1;86110:14;;;;:::i;:::-;86096:28;;-1:-1:-1;;;;;86607:4:0;86603:27;86589:41;;-1:-1:-1;;;;;86660:2:0;86656:25;86644:37;;87022:4;87017:3;87013:14;87007:21;86971:8;86931:10;-1:-1:-1;;;;;;;;;;;86818:1:0;86761;86738:319;87345:1;87307:336;87381:3;87372:7;87369:16;87307:336;;87617:7;87611:4;87607:18;87602:3;87598:28;87592:35;87582:8;87570:10;-1:-1:-1;;;;;;;;;;;87540:1:0;87537;87532:96;87430:1;87417:15;87307:336;;;87311:50;87701:2;-1:-1:-1;;;;;87671:47:0;87695:4;-1:-1:-1;;;;;87671:47:0;87685:8;-1:-1:-1;;;;;87671:47:0;;87705:3;87710:7;87671:47;;;;;;;:::i;:::-;;;;;;;;87731:44;87751:8;87761:4;87767:2;87771:3;87731:19;:44::i;:::-;87791:13;87807:14;77750:13;;;77676:95;87807:14;87791:30;;87832:75;87868:8;87878:4;87884:2;87888:3;87893:7;87902:4;87832:35;:75::i;:::-;87940:5;87922:14;77750:13;;;77676:95;87922:14;:23;87918:48;;87954:12;;-1:-1:-1;;;87954:12:0;;;;;;;;;;;94378:1816;-1:-1:-1;;;;;94484:18:0;;94481:77;;94525:21;;-1:-1:-1;;;94525:21:0;;;;;;;;;;;94481:77;77750:13;;45599:10;;94662:24;94703:6;-1:-1:-1;;;;;94689:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;94689:21:0;;94662:48;;94721:20;94758:6;-1:-1:-1;;;;;94744:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;94744:21:0;;94721:44;;94807:9;94803:339;94826:6;94822:1;:10;94803:339;;;94871:1;94858:7;94866:1;94858:10;;;;;;;;:::i;:::-;;;;;;;;;;;:14;;;;-1:-1:-1;;;;;94904:12:0;;94891:10;94904:12;;;:6;:12;;;;;;:36;;94929:10;94904:24;:36::i;:::-;94891:49;;-1:-1:-1;;94962:2:0;:25;94959:62;;94996:25;;-1:-1:-1;;;94996:25:0;;;;;;;;;;;94959:62;95049:2;95040:3;95044:1;95040:6;;;;;;;;:::i;:::-;;;;;;;;;;;:11;;;;-1:-1:-1;;;;;95070:12:0;;;;;;:6;:12;;;;;;;65298:1;65289:10;;;65278:22;;;;;;;;:48;;65320:4;65312:12;;65306:19;;;65304:22;65278:48;;;65289:10;;-1:-1:-1;94834:3:0;94803:339;;;;95293:18;;95336:10;:6;95345:1;95336:10;:::i;:::-;95322:24;;-1:-1:-1;;;;;95401:4:0;95397:27;95383:41;;95609:4;95604:3;95600:14;95594:21;95574:1;95545:10;-1:-1:-1;;;;;;;;;;;95481:1:0;95461;95438:192;95684:1;95646:264;95720:3;95711:7;95708:16;95646:264;;95884:7;95878:4;95874:18;95869:3;95865:28;95859:35;95856:1;95844:10;-1:-1:-1;;;;;;;;;;;95814:1:0;95811;95806:89;95769:1;95756:15;95646:264;;;95650:50;95936:6;95946:1;95936:11;95933:176;;96006:1;-1:-1:-1;;;;;95967:53:0;95992:4;-1:-1:-1;;;;;95967:53:0;95982:8;-1:-1:-1;;;;;95967:53:0;;96010:3;96014:1;96010:6;;;;;;;;:::i;:::-;;;;;;;96018:1;95967:53;;;;;;18455:25:1;;;18511:2;18496:18;;18489:34;18443:2;18428:18;;18281:248;95967:53:0;;;;;;;;95933:176;;;96092:1;-1:-1:-1;;;;;96054:55:0;96078:4;-1:-1:-1;;;;;96054:55:0;96068:8;-1:-1:-1;;;;;96054:55:0;;96096:3;96101:7;96054:55;;;;;;;:::i;:::-;;;;;;;;95933:176;96132:52;96152:8;96162:4;96176:1;96180:3;96132:19;:52::i;:::-;94470:1724;;;;;;94378:1816;;:::o;89721:1687::-;89826:20;;-1:-1:-1;;;;;89890:16:0;;89887:74;;89930:19;;-1:-1:-1;;;89930:19:0;;;;;;;;;;;89887:74;89974:6;89984:1;89974:11;89971:68;;90009:18;;-1:-1:-1;;;90009:18:0;;;;;;;;;;;89971:68;45599:10;90115:6;-1:-1:-1;;;;;90101:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;90101:21:0;;90095:27;;90157:6;-1:-1:-1;;;;;90143:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;90143:21:0;;90133:31;;90175:20;90198:14;77750:13;;;77676:95;90198:14;90175:37;;90288:12;90278:6;-1:-1:-1;;90258:26:0;:42;;90250:77;;;;-1:-1:-1;;;90250:77:0;;19947:2:1;90250:77:0;;;19929:21:1;19986:2;19966:18;;;19959:30;-1:-1:-1;;;20005:18:1;;;19998:52;20067:18;;90250:77:0;19745:346:1;90250:77:0;90346:9;90342:129;90365:6;90361:1;:10;90342:129;;;90421:1;90406:12;:16;90397:3;90401:1;90397:6;;;;;;;;:::i;:::-;;;;;;:25;;;;;90454:1;90441:7;90449:1;90441:10;;;;;;;;:::i;:::-;;;;;;;;;;:14;90373:3;;90342:129;;;;-1:-1:-1;;;;;90566:10:0;;;;;;:6;:10;;;;;:41;;90586:12;90600:6;90566:19;:41::i;:::-;90635:6;90618:13;;:23;;;;;;;:::i;:::-;;;;-1:-1:-1;90654:16:0;;-1:-1:-1;90654:16:0;90695:21;90710:6;90695:12;:21;:::i;:::-;90681:35;;-1:-1:-1;;;;;90769:2:0;90765:25;90753:37;;90958:12;90931:8;90911:1;-1:-1:-1;;;;;;;;;;;90847:1:0;90827;90804:181;91057:1;91043:12;91039:20;91001:253;91094:3;91085:7;91082:16;91001:253;;91231:7;91221:8;91218:1;-1:-1:-1;;;;;;;;;;;91188:1:0;91185;91180:59;91143:1;91130:15;91001:253;;;91005:69;91318:2;-1:-1:-1;;;;;91282:53:0;91314:1;-1:-1:-1;;;;;91282:53:0;91296:8;-1:-1:-1;;;;;91282:53:0;;91322:3;91327:7;91282:53;;;;;;;:::i;:::-;;;;;;;;91348:50;91368:8;91386:1;91390:2;91394:3;91348:19;:50::i;:::-;89874:1534;;;;89721:1687;;;;;:::o;48666:191::-;48740:16;48759:6;;-1:-1:-1;;;;;48776:17:0;;;-1:-1:-1;;;;;;48776:17:0;;;;;;48809:40;;48759:6;;;;;;;48809:40;;48740:16;48809:40;48729:128;48666:191;:::o;77869:114::-;77916:7;77588:1;77750:13;;77943:32;;;;:::i;:::-;77936:39;;77869:114;:::o;96340:331::-;96495:8;-1:-1:-1;;;;;96486:17:0;:5;-1:-1:-1;;;;;96486:17:0;;96478:71;;;;-1:-1:-1;;;96478:71:0;;20298:2:1;96478:71:0;;;20280:21:1;20337:2;20317:18;;;20310:30;20376:34;20356:18;;;20349:62;-1:-1:-1;;;20427:18:1;;;20420:39;20476:19;;96478:71:0;20096:405:1;96478:71:0;-1:-1:-1;;;;;96560:25:0;;;;;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;:46;;-1:-1:-1;;96560:46:0;;;;;;;;;;96622:41;;1159::1;;;96622::0;;1132:18:1;96622:41:0;;;;;;;96340:331;;;:::o;79221:105::-;79281:13;79314:4;79307:11;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79221:105;;;:::o;42444:718::-;42500:13;42551:14;42568:17;42579:5;42568:10;:17::i;:::-;42588:1;42568:21;42551:38;;42604:20;42638:6;-1:-1:-1;;;;;42627:18:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;42627:18:0;-1:-1:-1;42604:41:0;-1:-1:-1;42769:28:0;;;42785:2;42769:28;42826:290;-1:-1:-1;;42858:5:0;-1:-1:-1;;;42995:2:0;42984:14;;42979:32;42858:5;42966:46;43058:2;43049:11;;;-1:-1:-1;43079:21:0;42826:290;43079:21;-1:-1:-1;43137:6:0;42444:718;-1:-1:-1;;;42444:718:0:o;105390:443::-;-1:-1:-1;;;;;105503:19:0;;105499:91;;105546:32;;-1:-1:-1;;;105546:32:0;;105575:1;105546:32;;;3614:51:1;3587:18;;105546:32:0;3468:203:1;105499:91:0;-1:-1:-1;;;;;105604:21:0;;105600:92;;105649:31;;-1:-1:-1;;;105649:31:0;;105677:1;105649:31;;;3614:51:1;3587:18;;105649:31:0;3468:203:1;105600:92:0;-1:-1:-1;;;;;105702:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;:35;;;105748:78;;;;105799:7;-1:-1:-1;;;;;105783:31:0;105792:5;-1:-1:-1;;;;;105783:31:0;;105808:5;105783:31;;;;597:25:1;;585:2;570:18;;451:177;105783:31:0;;;;;;;;105390:443;;;;:::o;101115:162::-;101224:16;;;101238:1;101224:16;;;;;;;;;101181:22;;101224:16;;;;;;;;;;;-1:-1:-1;101224:16:0;101216:24;;101262:7;101251:5;101257:1;101251:8;;;;;;;;:::i;:::-;;;;;;:18;;;;;101115:162;;;:::o;109466:716::-;-1:-1:-1;;;;;109637:13:0;;;;;;:9;:13;;;;;;;;109633:461;;109692:9;;-1:-1:-1;;;;;109675:13:0;;;;;;:9;:13;;;;;;:26;;109667:70;;;;-1:-1:-1;;;109667:70:0;;20708:2:1;109667:70:0;;;20690:21:1;20747:2;20727:18;;;20720:30;20786:33;20766:18;;;20759:61;20837:18;;109667:70:0;20506:355:1;109667:70:0;109756:13;;;;109752:331;;;109809:9;109798:21;;;;:10;:21;;;;;;109822:12;-1:-1:-1;109790:84:0;;;;-1:-1:-1;;;109790:84:0;;21068:2:1;109790:84:0;;;21050:21:1;21107:2;21087:18;;;21080:30;21146:34;21126:18;;;21119:62;-1:-1:-1;;;21197:18:1;;;21190:34;21241:19;;109790:84:0;20866:400:1;109790:84:0;109904:9;109893:21;;;;:10;:21;;;;;109917:12;109893:36;;-1:-1:-1;;;;;109958:23:0;;;:28;:67;;;;-1:-1:-1;109998:9:0;109990:30;:35;109958:67;109950:117;;;;-1:-1:-1;;;109950:117:0;;21473:2:1;109950:117:0;;;21455:21:1;21512:2;21492:18;;;21485:30;21551:34;21531:18;;;21524:62;-1:-1:-1;;;21602:18:1;;;21595:35;21647:19;;109950:117:0;21271:401:1;109950:117:0;110124:50;105841:487;98907:1392;-1:-1:-1;;;;;99122:14:0;;;:18;99118:1174;;99161:57;;-1:-1:-1;;;99161:57:0;;-1:-1:-1;;;99161:57:0;;;21821:52:1;-1:-1:-1;;;;;99161:29:0;;;;;21794:18:1;;99161:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;99157:1124;;;99243:72;;-1:-1:-1;;;99243:72:0;;-1:-1:-1;;;;;99243:38:0;;;;;:72;;99282:8;;99292:4;;99298:2;;99302:6;;99310:4;;99243:72;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;99243:72:0;;;;;;;;-1:-1:-1;;99243:72:0;;;;;;;;;;;;:::i;:::-;;;99239:495;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;99609:6;99602:14;;-1:-1:-1;;;99602:14:0;;;;;;;;:::i;99239:495::-;;;99673:41;;-1:-1:-1;;;99673:41:0;;;;;;;;;;;99239:495;-1:-1:-1;;;;;;99369:55:0;;-1:-1:-1;;;99369:55:0;99365:160;;99460:41;;-1:-1:-1;;;99460:41:0;;;;;;;;;;;99365:160;99316:228;99157:1124;;;99791:61;;-1:-1:-1;;;99791:61:0;;-1:-1:-1;;;;;99791:35:0;;;;;:61;;99827:8;;99837:4;;99843:2;;99847:4;;99791:61;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;99791:61:0;;;;;;;;-1:-1:-1;;99791:61:0;;;;;;;;;;;;:::i;:::-;;;99787:479;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;100206:40;;-1:-1:-1;;;100206:40:0;;;;;;;;;;;99787:479;-1:-1:-1;;;;;;99906:52:0;;-1:-1:-1;;;99906:52:0;99902:156;;99994:40;;-1:-1:-1;;;99994:40:0;;;;;;;;;;;99902:156;99853:224;99787:479;98907:1392;;;;;;:::o;103372:1872::-;-1:-1:-1;;;;;103491:15:0;;;103469:19;103491:15;;;:9;:15;;;;;;;103537:13;;;;;;;;103565:19;;;103561:109;;;103608:50;;-1:-1:-1;;;103608:50:0;;-1:-1:-1;;;;;18754:32:1;;103608:50:0;;;18736:51:1;18803:18;;;18796:34;;;18846:18;;;18839:34;;;18709:18;;103608:50:0;18534:345:1;103561:109:0;103780:2;-1:-1:-1;;;;;103772:10:0;:4;-1:-1:-1;;;;;103772:10:0;;103769:1425;;-1:-1:-1;;;;;103908:15:0;;;;;;;:9;:15;;;;;;103926:19;;;103908:37;;104084:13;;;;;;104100:17;;;104084:33;;104149:1034;;;;-1:-1:-1;;;;;104252:15:0;;104241:8;104252:15;;;:9;:15;;;;;;;;;104286:250;;104319:22;104400:12;104377:19;104391:5;104377:11;:19;:::i;:::-;104376:36;;;;:::i;:::-;104345:26;104359:12;104345:11;:26;:::i;:::-;104344:69;;;;:::i;:::-;104319:94;-1:-1:-1;104439:18:0;;104436:80;;104484:32;104495:4;104501:14;104484:10;:32::i;:::-;104296:240;104286:250;-1:-1:-1;;;;;104628:13:0;;;;;;:9;:13;;;;;;;;104623:545;;104669:10;;104683:1;104669:15;:22;;;;;104688:3;104669:22;:41;;;;-1:-1:-1;47399:7:0;47426:6;-1:-1:-1;;;;;104695:15:0;;;47426:6;;104695:15;104669:41;104666:483;;;-1:-1:-1;;;;;104801:13:0;;;;;;:9;:13;;;;;:20;;-1:-1:-1;;104801:20:0;104817:4;104801:20;;;104861:1;104848:10;:14;104666:483;;;104919:22;104984:24;104996:12;104984:9;:24;:::i;:::-;104967:12;104946:17;104958:5;104946:9;:17;:::i;:::-;104945:34;;;;:::i;:::-;104944:65;;;;:::i;:::-;104919:90;-1:-1:-1;105039:18:0;;105036:89;;105088:37;105106:2;105110:14;105088:17;:37::i;:::-;;;105036:89;104892:257;104666:483;104158:1025;104149:1034;105226:2;-1:-1:-1;;;;;105211:25:0;105220:4;-1:-1:-1;;;;;105211:25:0;-1:-1:-1;;;;;;;;;;;105230:5:0;105211:25;;;;597::1;;585:2;570:18;;451:177;105211:25:0;;;;;;;;103458:1786;;103372:1872;;;;:::o;58556:464::-;58920:12;58793:11;58786:1;58782:9;;;58778:27;58771:35;;58858:1;58854:9;;;58865:11;58850:27;;;58829:19;;58825:53;58912:1;58908:9;;;58901:17;58897:36;58986:13;58979:21;58974:3;58970:31;-1:-1:-1;;58742:10:0;;;;58959:1;58955:13;58952:50;;58556:464::o;100307:800::-;-1:-1:-1;;;;;100547:14:0;;;:18;100543:557;;100586:79;;-1:-1:-1;;;100586:79:0;;-1:-1:-1;;;;;100586:43:0;;;;;:79;;100630:8;;100640:4;;100646:3;;100651:7;;100660:4;;100586:79;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;100586:79:0;;;;;;;;-1:-1:-1;;100586:79:0;;;;;;;;;;;;:::i;:::-;;;100582:507;;;;:::i;:::-;-1:-1:-1;;;;;;100747:60:0;;-1:-1:-1;;;100747:60:0;100743:157;;100839:41;;-1:-1:-1;;;100839:41:0;;;;;;;;;;;70489:1230;70807:1;70803:14;;;70599:19;70831:20;;;70872:4;70865:25;;;71045:4;71029:21;;71023:28;-1:-1:-1;;70773:6:0;70803:14;70922:4;70928:11;;70918:22;71011:41;;;70999:54;;71092:14;;71077:30;;71067:356;;71128:280;-1:-1:-1;71173:24:0;;71247:4;71240:20;;;71318:4;71302:21;;71296:28;71364:14;;71349:30;;71346:43;71128:280;71346:43;71128:280;71448:15;;71444:268;;71510:22;71521:10;56512:66;56436:4;56457:34;56062:9;;56059:1;56055:17;56084:34;56081:41;-1:-1:-1;56078:1:0;56074:49;56052:72;56179:9;;;-1:-1:-1;;;;;56156:33:0;56153:1;56149:41;56143:48;56238:9;;;56226:10;56223:25;56220:1;56216:33;56210:40;56293:9;;;56285:6;56282:21;56279:1;56275:29;56269:36;56346:9;;;56340:4;56337:19;56334:1;56330:27;56324:34;56446:9;;;56442:50;56432:61;56427:152;56421:159;;55910:688;71510:22;71505:1;71495:11;;;71494:38;71661:23;;;71658:1;71654:31;71638:48;;-1:-1:-1;71444:268:0;70625:1094;;70489:1230;;;;:::o;67042:1129::-;67217:1;67213:6;67257:4;67250:5;67246:16;67289:11;67283:4;67276:25;67335:5;67332:1;67328:13;67322:4;67315:27;67389:3;67380:6;67373:5;67369:18;67366:27;67356:646;;67443:4;67433:21;;67449:4;67433:21;;67495:18;;67515:15;;;67492:39;67472:60;;67642:18;;;;67714:4;67690:29;;;-1:-1:-1;67564:19:0;;;67639:1;67635:26;67618:44;67765:184;67790:9;67782:6;67779:21;67765:184;;67867:6;67861:4;67854:20;67926:3;67919:4;67913;67903:21;67896:34;67826:1;67818:6;67814:14;67804:24;;67765:184;;;-1:-1:-1;67974:4:0;67967:20;67356:646;68051:4;68045;68035:21;68146:3;68137:6;68132:3;68128:16;68124:26;68117:5;68113:38;68099:11;68093:18;68090:62;68077:11;68070:83;;;;67042:1129;;;:::o;39005:948::-;39058:7;;-1:-1:-1;;;39136:17:0;;39132:106;;-1:-1:-1;;;39174:17:0;;;-1:-1:-1;39220:2:0;39210:12;39132:106;39265:8;39256:5;:17;39252:106;;39303:8;39294:17;;;-1:-1:-1;39340:2:0;39330:12;39252:106;39385:8;39376:5;:17;39372:106;;39423:8;39414:17;;;-1:-1:-1;39460:2:0;39450:12;39372:106;39505:7;39496:5;:16;39492:103;;39542:7;39533:16;;;-1:-1:-1;39578:1:0;39568:11;39492:103;39622:7;39613:5;:16;39609:103;;39659:7;39650:16;;;-1:-1:-1;39695:1:0;39685:11;39609:103;39739:7;39730:5;:16;39726:103;;39776:7;39767:16;;;-1:-1:-1;39812:1:0;39802:11;39726:103;39856:7;39847:5;:16;39843:68;;39894:1;39884:11;39939:6;39005:948;-1:-1:-1;;39005:948:0:o;14:173:1:-;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:70;;177:1;174;167:12;192:254;260:6;268;321:2;309:9;300:7;296:23;292:32;289:52;;;337:1;334;327:12;289:52;360:29;379:9;360:29;:::i;:::-;350:39;436:2;421:18;;;;408:32;;-1:-1:-1;;;192:254:1:o;633:131::-;-1:-1:-1;;;;;;707:32:1;;697:43;;687:71;;754:1;751;744:12;769:245;827:6;880:2;868:9;859:7;855:23;851:32;848:52;;;896:1;893;886:12;848:52;935:9;922:23;954:30;978:5;954:30;:::i;1211:127::-;1272:10;1267:3;1263:20;1260:1;1253:31;1303:4;1300:1;1293:15;1327:4;1324:1;1317:15;1343:249;1453:2;1434:13;;-1:-1:-1;;1430:27:1;1418:40;;-1:-1:-1;;;;;1473:34:1;;1509:22;;;1470:62;1467:88;;;1535:18;;:::i;:::-;1571:2;1564:22;-1:-1:-1;;1343:249:1:o;1597:469::-;1662:5;-1:-1:-1;;;;;1688:6:1;1685:30;1682:56;;;1718:18;;:::i;:::-;1767:2;1761:9;1779:69;1836:2;1815:15;;-1:-1:-1;;1811:29:1;1842:4;1807:40;1761:9;1779:69;:::i;:::-;1866:6;1857:15;;1896:6;1888;1881:22;1936:3;1927:6;1922:3;1918:16;1915:25;1912:45;;;1953:1;1950;1943:12;1912:45;2003:6;1998:3;1991:4;1983:6;1979:17;1966:44;2058:1;2051:4;2042:6;2034;2030:19;2026:30;2019:41;;1597:469;;;;;:::o;2071:451::-;2140:6;2193:2;2181:9;2172:7;2168:23;2164:32;2161:52;;;2209:1;2206;2199:12;2161:52;2249:9;2236:23;-1:-1:-1;;;;;2274:6:1;2271:30;2268:50;;;2314:1;2311;2304:12;2268:50;2337:22;;2390:4;2382:13;;2378:27;-1:-1:-1;2368:55:1;;2419:1;2416;2409:12;2368:55;2442:74;2508:7;2503:2;2490:16;2485:2;2481;2477:11;2442:74;:::i;2527:250::-;2612:1;2622:113;2636:6;2633:1;2630:13;2622:113;;;2712:11;;;2706:18;2693:11;;;2686:39;2658:2;2651:10;2622:113;;;-1:-1:-1;;2769:1:1;2751:16;;2744:27;2527:250::o;2782:271::-;2824:3;2862:5;2856:12;2889:6;2884:3;2877:19;2905:76;2974:6;2967:4;2962:3;2958:14;2951:4;2944:5;2940:16;2905:76;:::i;:::-;3035:2;3014:15;-1:-1:-1;;3010:29:1;3001:39;;;;3042:4;2997:50;;2782:271;-1:-1:-1;;2782:271:1:o;3058:220::-;3207:2;3196:9;3189:21;3170:4;3227:45;3268:2;3257:9;3253:18;3245:6;3227:45;:::i;3283:180::-;3342:6;3395:2;3383:9;3374:7;3370:23;3366:32;3363:52;;;3411:1;3408;3401:12;3363:52;-1:-1:-1;3434:23:1;;3283:180;-1:-1:-1;3283:180:1:o;3676:328::-;3753:6;3761;3769;3822:2;3810:9;3801:7;3797:23;3793:32;3790:52;;;3838:1;3835;3828:12;3790:52;3861:29;3880:9;3861:29;:::i;:::-;3851:39;;3909:38;3943:2;3932:9;3928:18;3909:38;:::i;:::-;3899:48;;3994:2;3983:9;3979:18;3966:32;3956:42;;3676:328;;;;;:::o;4009:322::-;4086:6;4094;4102;4155:2;4143:9;4134:7;4130:23;4126:32;4123:52;;;4171:1;4168;4161:12;4123:52;4194:29;4213:9;4194:29;:::i;:::-;4184:39;4270:2;4255:18;;4242:32;;-1:-1:-1;4321:2:1;4306:18;;;4293:32;;4009:322;-1:-1:-1;;;4009:322:1:o;4336:183::-;4396:4;-1:-1:-1;;;;;4421:6:1;4418:30;4415:56;;;4451:18;;:::i;:::-;-1:-1:-1;4496:1:1;4492:14;4508:4;4488:25;;4336:183::o;4524:724::-;4578:5;4631:3;4624:4;4616:6;4612:17;4608:27;4598:55;;4649:1;4646;4639:12;4598:55;4685:6;4672:20;4711:4;4734:43;4774:2;4734:43;:::i;:::-;4806:2;4800:9;4818:31;4846:2;4838:6;4818:31;:::i;:::-;4884:18;;;4976:1;4972:10;;;;4960:23;;4956:32;;;4918:15;;;;-1:-1:-1;5000:15:1;;;4997:35;;;5028:1;5025;5018:12;4997:35;5064:2;5056:6;5052:15;5076:142;5092:6;5087:3;5084:15;5076:142;;;5158:17;;5146:30;;5196:12;;;;5109;;5076:142;;;-1:-1:-1;5236:6:1;4524:724;-1:-1:-1;;;;;;4524:724:1:o;5253:221::-;5295:5;5348:3;5341:4;5333:6;5329:17;5325:27;5315:55;;5366:1;5363;5356:12;5315:55;5388:80;5464:3;5455:6;5442:20;5435:4;5427:6;5423:17;5388:80;:::i;5479:943::-;5633:6;5641;5649;5657;5665;5718:3;5706:9;5697:7;5693:23;5689:33;5686:53;;;5735:1;5732;5725:12;5686:53;5758:29;5777:9;5758:29;:::i;:::-;5748:39;;5806:38;5840:2;5829:9;5825:18;5806:38;:::i;:::-;5796:48;;5895:2;5884:9;5880:18;5867:32;-1:-1:-1;;;;;5959:2:1;5951:6;5948:14;5945:34;;;5975:1;5972;5965:12;5945:34;5998:61;6051:7;6042:6;6031:9;6027:22;5998:61;:::i;:::-;5988:71;;6112:2;6101:9;6097:18;6084:32;6068:48;;6141:2;6131:8;6128:16;6125:36;;;6157:1;6154;6147:12;6125:36;6180:63;6235:7;6224:8;6213:9;6209:24;6180:63;:::i;:::-;6170:73;;6296:3;6285:9;6281:19;6268:33;6252:49;;6326:2;6316:8;6313:16;6310:36;;;6342:1;6339;6332:12;6310:36;;6365:51;6408:7;6397:8;6386:9;6382:24;6365:51;:::i;:::-;6355:61;;;5479:943;;;;;;;;:::o;6616:1208::-;6734:6;6742;6795:2;6783:9;6774:7;6770:23;6766:32;6763:52;;;6811:1;6808;6801:12;6763:52;6851:9;6838:23;-1:-1:-1;;;;;6921:2:1;6913:6;6910:14;6907:34;;;6937:1;6934;6927:12;6907:34;6975:6;6964:9;6960:22;6950:32;;7020:7;7013:4;7009:2;7005:13;7001:27;6991:55;;7042:1;7039;7032:12;6991:55;7078:2;7065:16;7100:4;7123:43;7163:2;7123:43;:::i;:::-;7195:2;7189:9;7207:31;7235:2;7227:6;7207:31;:::i;:::-;7273:18;;;7361:1;7357:10;;;;7349:19;;7345:28;;;7307:15;;;;-1:-1:-1;7385:19:1;;;7382:39;;;7417:1;7414;7407:12;7382:39;7441:11;;;;7461:148;7477:6;7472:3;7469:15;7461:148;;;7543:23;7562:3;7543:23;:::i;:::-;7531:36;;7494:12;;;;7587;;;;7461:148;;;7628:6;-1:-1:-1;;7672:18:1;;7659:32;;-1:-1:-1;;7703:16:1;;;7700:36;;;7732:1;7729;7722:12;7700:36;;7755:63;7810:7;7799:8;7788:9;7784:24;7755:63;:::i;:::-;7745:73;;;6616:1208;;;;;:::o;7829:435::-;7882:3;7920:5;7914:12;7947:6;7942:3;7935:19;7973:4;8002:2;7997:3;7993:12;7986:19;;8039:2;8032:5;8028:14;8060:1;8070:169;8084:6;8081:1;8078:13;8070:169;;;8145:13;;8133:26;;8179:12;;;;8214:15;;;;8106:1;8099:9;8070:169;;;-1:-1:-1;8255:3:1;;7829:435;-1:-1:-1;;;;;7829:435:1:o;8269:261::-;8448:2;8437:9;8430:21;8411:4;8468:56;8520:2;8509:9;8505:18;8497:6;8468:56;:::i;8535:118::-;8621:5;8614:13;8607:21;8600:5;8597:32;8587:60;;8643:1;8640;8633:12;8658:315;8723:6;8731;8784:2;8772:9;8763:7;8759:23;8755:32;8752:52;;;8800:1;8797;8790:12;8752:52;8823:29;8842:9;8823:29;:::i;:::-;8813:39;;8902:2;8891:9;8887:18;8874:32;8915:28;8937:5;8915:28;:::i;:::-;8962:5;8952:15;;;8658:315;;;;;:::o;8978:186::-;9037:6;9090:2;9078:9;9069:7;9065:23;9061:32;9058:52;;;9106:1;9103;9096:12;9058:52;9129:29;9148:9;9129:29;:::i;9169:260::-;9237:6;9245;9298:2;9286:9;9277:7;9273:23;9269:32;9266:52;;;9314:1;9311;9304:12;9266:52;9337:29;9356:9;9337:29;:::i;:::-;9327:39;;9385:38;9419:2;9408:9;9404:18;9385:38;:::i;:::-;9375:48;;9169:260;;;;;:::o;9434:606::-;9538:6;9546;9554;9562;9570;9623:3;9611:9;9602:7;9598:23;9594:33;9591:53;;;9640:1;9637;9630:12;9591:53;9663:29;9682:9;9663:29;:::i;:::-;9653:39;;9711:38;9745:2;9734:9;9730:18;9711:38;:::i;:::-;9701:48;;9796:2;9785:9;9781:18;9768:32;9758:42;;9847:2;9836:9;9832:18;9819:32;9809:42;;9902:3;9891:9;9887:19;9874:33;-1:-1:-1;;;;;9922:6:1;9919:30;9916:50;;;9962:1;9959;9952:12;9916:50;9985:49;10026:7;10017:6;10006:9;10002:22;9985:49;:::i;10045:380::-;10124:1;10120:12;;;;10167;;;10188:61;;10242:4;10234:6;10230:17;10220:27;;10188:61;10295:2;10287:6;10284:14;10264:18;10261:38;10258:161;;10341:10;10336:3;10332:20;10329:1;10322:31;10376:4;10373:1;10366:15;10404:4;10401:1;10394:15;10258:161;;10045:380;;;:::o;10556:545::-;10658:2;10653:3;10650:11;10647:448;;;10694:1;10719:5;10715:2;10708:17;10764:4;10760:2;10750:19;10834:2;10822:10;10818:19;10815:1;10811:27;10805:4;10801:38;10870:4;10858:10;10855:20;10852:47;;;-1:-1:-1;10893:4:1;10852:47;10948:2;10943:3;10939:12;10936:1;10932:20;10926:4;10922:31;10912:41;;11003:82;11021:2;11014:5;11011:13;11003:82;;;11066:17;;;11047:1;11036:13;11003:82;;11277:1352;11403:3;11397:10;-1:-1:-1;;;;;11422:6:1;11419:30;11416:56;;;11452:18;;:::i;:::-;11481:97;11571:6;11531:38;11563:4;11557:11;11531:38;:::i;:::-;11525:4;11481:97;:::i;:::-;11633:4;;11697:2;11686:14;;11714:1;11709:663;;;;12416:1;12433:6;12430:89;;;-1:-1:-1;12485:19:1;;;12479:26;12430:89;-1:-1:-1;;11234:1:1;11230:11;;;11226:24;11222:29;11212:40;11258:1;11254:11;;;11209:57;12532:81;;11679:944;;11709:663;10503:1;10496:14;;;10540:4;10527:18;;-1:-1:-1;;11745:20:1;;;11863:236;11877:7;11874:1;11871:14;11863:236;;;11966:19;;;11960:26;11945:42;;12058:27;;;;12026:1;12014:14;;;;11893:19;;11863:236;;;11867:3;12127:6;12118:7;12115:19;12112:201;;;12188:19;;;12182:26;-1:-1:-1;;12271:1:1;12267:14;;;12283:3;12263:24;12259:37;12255:42;12240:58;12225:74;;12112:201;-1:-1:-1;;;;;12359:1:1;12343:14;;;12339:22;12326:36;;-1:-1:-1;11277:1352:1:o;12634:127::-;12695:10;12690:3;12686:20;12683:1;12676:31;12726:4;12723:1;12716:15;12750:4;12747:1;12740:15;12766:128;12833:9;;;12854:11;;;12851:37;;;12868:18;;:::i;12899:127::-;12960:10;12955:3;12951:20;12948:1;12941:31;12991:4;12988:1;12981:15;13015:4;13012:1;13005:15;13031:135;13070:3;13091:17;;;13088:43;;13111:18;;:::i;:::-;-1:-1:-1;13158:1:1;13147:13;;13031:135::o;13651:217::-;13691:1;13717;13707:132;;13761:10;13756:3;13752:20;13749:1;13742:31;13796:4;13793:1;13786:15;13824:4;13821:1;13814:15;13707:132;-1:-1:-1;13853:9:1;;13651:217::o;14231:168::-;14304:9;;;14335;;14352:15;;;14346:22;;14332:37;14322:71;;14373:18;;:::i;14404:722::-;14454:3;14495:5;14489:12;14524:36;14550:9;14524:36;:::i;:::-;14579:1;14596:18;;;14623:133;;;;14770:1;14765:355;;;;14589:531;;14623:133;-1:-1:-1;;14656:24:1;;14644:37;;14729:14;;14722:22;14710:35;;14701:45;;;-1:-1:-1;14623:133:1;;14765:355;14796:5;14793:1;14786:16;14825:4;14870:2;14867:1;14857:16;14895:1;14909:165;14923:6;14920:1;14917:13;14909:165;;;15001:14;;14988:11;;;14981:35;15044:16;;;;14938:10;;14909:165;;;14913:3;;;15103:6;15098:3;15094:16;15087:23;;14589:531;;;;;14404:722;;;;:::o;15131:389::-;15307:3;15335:38;15369:3;15361:6;15335:38;:::i;:::-;15402:6;15396:13;15418:65;15476:6;15472:2;15465:4;15457:6;15453:17;15418:65;:::i;:::-;15499:15;;15131:389;-1:-1:-1;;;;15131:389:1:o;15712:1452::-;-1:-1:-1;;;16305:55:1;;16383:13;;16287:3;;16405:75;16383:13;16468:2;16459:12;;16452:4;16440:17;;16405:75;:::i;:::-;-1:-1:-1;;;16539:2:1;16499:16;;;16531:11;;;16524:67;16616:13;;16638:78;16616:13;16700:4;16692:13;;;;16673:17;;16638:78;:::i;:::-;16783:66;16776:4;16735:17;;;;16768:13;;;16761:89;16879:66;16874:2;16866:11;;16859:87;16965:46;17007:2;16999:11;;16991:6;16965:46;:::i;:::-;16955:56;;17042:6;17036:13;17058:67;17116:8;17112:2;17105:4;17097:6;17093:17;17058:67;:::i;:::-;17141:17;;15712:1452;-1:-1:-1;;;;;;15712:1452:1:o;17169:1107::-;17681:29;17676:3;17669:42;17651:3;17740:6;17734:13;17756:75;17824:6;17819:2;17814:3;17810:12;17803:4;17795:6;17791:17;17756:75;:::i;:::-;17895:66;17890:2;17850:16;;;17882:11;;;17875:87;-1:-1:-1;;;17986:2:1;17978:11;;17971:63;18059:13;;18081:76;18059:13;18143:2;18135:11;;18128:4;18116:17;;18081:76;:::i;:::-;-1:-1:-1;;;18217:2:1;18176:17;;;;18209:11;;;18202:41;18267:2;18259:11;;17169:1107;-1:-1:-1;;;;17169:1107:1:o;18884:125::-;18949:9;;;18970:10;;;18967:36;;;18983:18;;:::i;19014:465::-;19271:2;19260:9;19253:21;19234:4;19297:56;19349:2;19338:9;19334:18;19326:6;19297:56;:::i;:::-;19401:9;19393:6;19389:22;19384:2;19373:9;19369:18;19362:50;19429:44;19466:6;19458;19429:44;:::i;:::-;19421:52;19014:465;-1:-1:-1;;;;;19014:465:1:o;21884:245::-;21951:6;22004:2;21992:9;21983:7;21979:23;21975:32;21972:52;;;22020:1;22017;22010:12;21972:52;22052:9;22046:16;22071:28;22093:5;22071:28;:::i;22134:561::-;-1:-1:-1;;;;;22431:15:1;;;22413:34;;22483:15;;22478:2;22463:18;;22456:43;22530:2;22515:18;;22508:34;;;22573:2;22558:18;;22551:34;;;22393:3;22616;22601:19;;22594:32;;;22356:4;;22643:46;;22669:19;;22661:6;22643:46;:::i;:::-;22635:54;22134:561;-1:-1:-1;;;;;;;22134:561:1:o;22700:249::-;22769:6;22822:2;22810:9;22801:7;22797:23;22793:32;22790:52;;;22838:1;22835;22828:12;22790:52;22870:9;22864:16;22889:30;22913:5;22889:30;:::i;22954:179::-;22989:3;23031:1;23013:16;23010:23;23007:120;;;23077:1;23074;23071;23056:23;-1:-1:-1;23114:1:1;23108:8;23103:3;23099:18;23007:120;22954:179;:::o;23138:671::-;23177:3;23219:4;23201:16;23198:26;23195:39;;;23138:671;:::o;23195:39::-;23261:2;23255:9;-1:-1:-1;;23326:16:1;23322:25;;23319:1;23255:9;23298:50;23377:4;23371:11;23401:16;-1:-1:-1;;;;;23507:2:1;23500:4;23492:6;23488:17;23485:25;23480:2;23472:6;23469:14;23466:45;23463:58;;;23514:5;;;;;23138:671;:::o;23463:58::-;23551:6;23545:4;23541:17;23530:28;;23587:3;23581:10;23614:2;23606:6;23603:14;23600:27;;;23620:5;;;;;;23138:671;:::o;23600:27::-;23704:2;23685:16;23679:4;23675:27;23671:36;23664:4;23655:6;23650:3;23646:16;23642:27;23639:69;23636:82;;;23711:5;;;;;;23138:671;:::o;23636:82::-;23727:57;23778:4;23769:6;23761;23757:19;23753:30;23747:4;23727:57;:::i;:::-;-1:-1:-1;23800:3:1;;23138:671;-1:-1:-1;;;;;23138:671:1:o;23814:489::-;-1:-1:-1;;;;;24083:15:1;;;24065:34;;24135:15;;24130:2;24115:18;;24108:43;24182:2;24167:18;;24160:34;;;24230:3;24225:2;24210:18;;24203:31;;;24008:4;;24251:46;;24277:19;;24269:6;24251:46;:::i;:::-;24243:54;23814:489;-1:-1:-1;;;;;;23814:489:1:o;24308:827::-;-1:-1:-1;;;;;24705:15:1;;;24687:34;;24757:15;;24752:2;24737:18;;24730:43;24667:3;24804:2;24789:18;;24782:31;;;24630:4;;24836:57;;24873:19;;24865:6;24836:57;:::i;:::-;24941:9;24933:6;24929:22;24924:2;24913:9;24909:18;24902:50;24975:44;25012:6;25004;24975:44;:::i;:::-;24961:58;;25068:9;25060:6;25056:22;25050:3;25039:9;25035:19;25028:51;25096:33;25122:6;25114;25096:33;:::i;:::-;25088:41;24308:827;-1:-1:-1;;;;;;;;24308:827:1:o

Swarm Source

ipfs://33846d8f18b9e81ed13c5ff6685615735cb957e35478c0ff3cb0c5155466c5d7
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.