ETH Price: $3,117.14 (+0.62%)
Gas: 4 Gwei

Token

Society of the Hourglass (SOTH)
 

Overview

Max Total Supply

0 SOTH

Holders

619

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
2 SOTH
0x54a89f518c17097047188704ca2d6d8d7ef3af7e
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:
SocietyOfTheHourglass

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 72500 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-01-03
*/

// Dependency file: @openzeppelin/contracts/utils/introspection/IERC165.sol

// SPDX-License-Identifier: MIT

// pragma solidity ^0.8.0;

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


// Dependency file: @openzeppelin/contracts/token/ERC721/IERC721.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

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

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

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

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

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

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

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


// Dependency file: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol


// pragma solidity ^0.8.0;

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


// Dependency file: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

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


// Dependency file: @openzeppelin/contracts/utils/Address.sol


// pragma solidity ^0.8.0;

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

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

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

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

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

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

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

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

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


// Dependency file: @openzeppelin/contracts/utils/Context.sol


// pragma solidity ^0.8.0;

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

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


// Dependency file: @openzeppelin/contracts/utils/Strings.sol


// pragma solidity ^0.8.0;

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

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

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

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

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


// Dependency file: @openzeppelin/contracts/utils/introspection/ERC165.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

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


// Dependency file: @openzeppelin/contracts/token/ERC721/ERC721.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
// import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
// import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
// import "@openzeppelin/contracts/utils/Address.sol";
// import "@openzeppelin/contracts/utils/Context.sol";
// import "@openzeppelin/contracts/utils/Strings.sol";
// import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

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

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        require(operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

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

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @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.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

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

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

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

        _balances[owner] -= 1;
        delete _owners[tokenId];

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

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

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

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

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

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


// Dependency file: @openzeppelin/contracts/interfaces/IERC165.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/utils/introspection/IERC165.sol";


// Dependency file: @openzeppelin/contracts/interfaces/IERC2981.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/interfaces/IERC165.sol";

/**
 * @dev Interface for the NFT Royalty Standard
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Called with the sale price to determine how much royalty is owed and to whom.
     * @param tokenId - the NFT asset queried for royalty information
     * @param salePrice - the sale price of the NFT asset specified by `tokenId`
     * @return receiver - address of who should be sent the royalty payment
     * @return royaltyAmount - the royalty payment amount for `salePrice`
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        returns (address receiver, uint256 royaltyAmount);
}


// Dependency file: @openzeppelin/contracts/access/Ownable.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/utils/Context.sol";

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

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

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

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

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

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}


// Dependency file: @openzeppelin/contracts/utils/Counters.sol


// pragma solidity ^0.8.0;

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

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

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

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

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


// Dependency file: @openzeppelin/contracts/utils/cryptography/ECDSA.sol


// pragma solidity ^0.8.0;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s;
        uint8 v;
        assembly {
            s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            v := add(shr(255, vs), 27)
        }
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}


// Dependency file: @openzeppelin/contracts/utils/math/SafeMath.sol


// pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    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 substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    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.
     *
     * _Available since v3.4._
     */
    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.
     *
     * _Available since v3.4._
     */
    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.
     *
     * _Available since v3.4._
     */
    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 addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

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

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

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

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

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

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}


// Dependency file: contracts/Hashku.sol

// pragma solidity 0.8.9;

/*
*
* Hashku Contract
* 
* Contract by Matt Casanova [Twitter: @DevGuyThings]
* 
* To be used as base contract for ERC721 when minting on Hashku
*
*/

// import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
// import "@openzeppelin/contracts/interfaces/IERC2981.sol";
// import "@openzeppelin/contracts/access/Ownable.sol";
// import "@openzeppelin/contracts/utils/Address.sol";
// import "@openzeppelin/contracts/utils/Strings.sol";
// import "@openzeppelin/contracts/utils/Context.sol";
// import "@openzeppelin/contracts/utils/Counters.sol";
// import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
// import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract Hashku is Context, Ownable, ERC721, IERC2981 {
    using Address for address;
    using Strings for uint256;
    using Counters for Counters.Counter;
    using ECDSA for bytes32;

    Counters.Counter private tokenIdTracker;

    string public baseTokenURI;
    string public key = "SHOP";
    string public group = "init";
    uint256 public maxMintPerAddress;
    uint256 public maxMintPerTransaction;
    uint256 public maxTokens;
    uint256 public price;
    bool public isPublic;
    bool public isClosed;
    mapping(address => uint256) public tokensMinted;
    address public withdrawalAddress;
    address public verifySigner;
    uint256 public royaltyPercent;
    address public proxyRegistryAddress;

    event ContractUpdated(string _type);

    modifier onlyWithdrawer() {
        require(withdrawalAddress != address(0), "no_withdrawals");
        require(withdrawalAddress == _msgSender(), "not_allowed");
        _;
    }

    constructor(
        string memory _name, 
        string memory _symbol, 
        string memory _baseTokenURI,
        string memory _key,
        uint256 _maxTokens, 
        uint256 _maxMintPerAddress,
        uint256 _maxMintPerTransaction,
        uint256 _price,
        uint256 _royaltyPercent,
        address _withdrawalAddress
    ) ERC721(_name, _symbol) {
        baseTokenURI = _baseTokenURI;
        key = _key;
        maxTokens = _maxTokens;
        maxMintPerAddress = _maxMintPerAddress;
        maxMintPerTransaction = _maxMintPerTransaction;
        price = _price;
        royaltyPercent = _royaltyPercent;
        withdrawalAddress = _withdrawalAddress;
        verifySigner = _msgSender();
    }

    // support IERC2981
    function supportsInterface(bytes4 _interfaceId) public view virtual override (ERC721, IERC165) returns (bool) {
        return _interfaceId == type(IERC2981).interfaceId || super.supportsInterface(_interfaceId);
    }

    // return the token URI for a specific token
    function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {
        require(_exists(_tokenId), "no_token");

        return bytes(baseTokenURI).length > 0 ? string(abi.encodePacked(baseTokenURI, _tokenId.toString())) : "";
    }

    // internal mint function, incrementing token
    function mint(address _to) internal {
        _safeMint(_to, tokenIdTracker.current());
        tokenIdTracker.increment();
    }

    // owner sends NFTs to addresses
    function send(address[] calldata _addresses, uint256[] calldata _amounts) external virtual onlyOwner {
        require(_addresses.length == _amounts.length, "amount_mismatch");

        uint256 total;
        for (uint256 t = 0; t < _amounts.length; t++) {
            total += _amounts[t];
        }

        require(nextToken() + total <= maxTokens, "not_enough_tokens");

        delete total;

        for (uint256 i = 0; i < _addresses.length; i++) {
            for (uint256 a = 0; a < _amounts[i]; a++) {
                mint(_addresses[i]);
            }
        }
    }

    // buy NFTs - version without signature required for public mint
    function shop(uint256 _amount) external virtual payable {}

    // buy NFTs
    function shop(uint256 _amount, bytes memory _signature) external virtual payable {}

    // return the id for the next token that will be minted
    function nextToken() public view returns (uint256) {
        return tokenIdTracker.current();
    }

    // check if a msg sender is eligible to shop
    function eligible() public view virtual returns (bool) {
        if (isClosed) {
            return false;
        }

        return isPublic;
    }

    // owner can ONLY decrease the total number of available tokens
    function decreaseMaxTokens(uint256 _amount) external virtual onlyOwner {
        require(_amount < maxTokens, "only_decrease");
        maxTokens = _amount;
    }

    // owner set the contract to public mode
    function setIsPublic(bool _public) external virtual onlyOwner {
        isPublic = _public;
        emit ContractUpdated("isPublic");
    }

    // owner set the contract to closed
    function setIsClosed(bool _closed) external virtual onlyOwner {
        isClosed = _closed;
        emit ContractUpdated("isClosed");
    }

    // owner set the price of minting
    function setPrice(uint256 _price) external virtual onlyOwner {
        price = _price;
    }

    // set the maximum amount an address may mint
    function setMaxMintPerAddress(uint256 _amount) external virtual onlyOwner {
        maxMintPerAddress = _amount;
    }

    // set the maximum amount an address may mint
    function setMaxMintPerTransaction(uint256 _amount) external virtual onlyOwner {
        maxMintPerTransaction = _amount;
    }

    // owner set the contract key for signature verification
    function setKey(string calldata _key) external virtual onlyOwner {
        key = _key;
    }

    // set the current contract group for signature verification
    function setGroup(string memory _group) external virtual onlyOwner {
        group = _group;
        emit ContractUpdated("group");
    }

    // owner set a new base token URI
    function setBaseUri(string calldata _baseTokenURI) external virtual onlyOwner {
        baseTokenURI = _baseTokenURI;
    }

    // owner set a new address for signature verification
    function setVerifySigner(address _verifySigner) external virtual onlyOwner {
        verifySigner = _verifySigner;
    }

    // verify signature based on contract key, contract group, token amount, and the msg sender
    function verifySignature(
        bytes memory _signature
    ) internal view virtual returns (bool) {
        bytes32 _messageHash = keccak256(abi.encodePacked(key, group, _msgSender()));

        return _messageHash.toEthSignedMessageHash().recover(_signature) == verifySigner;
    }

    // set the royalty percent
    function setRoyaltyPercent(uint256 _amount) external virtual onlyOwner {
        royaltyPercent = _amount;
    }

    // EIP-2981 royaltyInfo
    function royaltyInfo(uint256 _tokenId, uint256 _salePrice) external view virtual override returns (address receiver, uint256 royaltyAmount) {
        require(_exists(_tokenId), "no_token");

        return (address(this), SafeMath.div(SafeMath.mul(_salePrice, royaltyPercent), 100));
    }

    // withdrawal address convenience method for pulling balance of contract
    function seeBalance() external view virtual onlyWithdrawer returns (uint256) {
        return address(this).balance;
    }

    // withdrawal address send an amount to an address
    function withdraw(address payable _to, uint256 _amount) external virtual onlyWithdrawer returns (bool) {
        require(_amount <= address(this).balance, "insufficient_funds");
        _to.transfer(_amount);
        return true;
    }

    // withdrawal address set a new withdrawal address
    function setWithdrawalAddress(address _address) external virtual onlyWithdrawer {
        withdrawalAddress = _address;
        // emit ContractUpdated("withdrawalAddress");
    }

    // owner can set the proxy registry access after deploy
    function setProxyRegistryAddress(address _proxy) external virtual onlyOwner {
        // OpenSea Rinkeby Address = "0xf57b2c51ded3a29e6891aba85459d600256cf317";
        // OpenSea Mainnet Address = "0xa5409ec958c83c3f309868babaca7c86dcb077c1";
        proxyRegistryAddress = _proxy;
    }

    // override isApprovedForAll to allow proxy address for OpenSea gasless listing
    function isApprovedForAll(address _owner, address _operator) public view virtual override returns (bool) {
        if (proxyRegistryAddress != address(0)) {
            ProxyRegistry _proxyRegistry = ProxyRegistry(proxyRegistryAddress);
            if (address(_proxyRegistry.proxies(_owner)) == _operator) {
                return true;
            }
        }

        return super.isApprovedForAll(_owner, _operator);
    }
}

contract OwnableDelegateProxy {}

contract ProxyRegistry {
    mapping(address => OwnableDelegateProxy) public proxies;
}


// Dependency file: contracts/imports/VerifySignature.sol


/*
*
* VerifySignature Contract
* 
* Contract by Matt Casanova [Twitter: @DevGuyThings]
* 
* Verify a signature generated off-chain
* To be used for helping avoid gas wars without having to whitelist addresses on contract
*
*/

// pragma solidity 0.8.9;

// import "@openzeppelin/contracts/access/Ownable.sol";

contract VerifySignature is Ownable {

    address public verifySigner;

    constructor() {
        verifySigner = msg.sender;
    }

    function setSigner(address _newSigner) public onlyOwner {
        verifySigner = _newSigner;
    }

    function getMessageHash(
        string memory _messageOne,
        string memory _messageTwo,
        uint _numberOne,
        uint _numberTwo,
        address _address
    ) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(_messageOne, _messageTwo, _numberOne, _numberTwo, _address));
    }

    function getEthSignedMessageHash(bytes32 _messageHash)
        internal
        pure
        returns (bytes32)
    {
        return
            keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)
            );
    }

    function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature)
        internal
        pure
        returns (address)
    {
        (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);

        return ecrecover(_ethSignedMessageHash, v, r, s);
    }

    function splitSignature(bytes memory _sig)
        internal
        pure
        returns (
            bytes32 r,
            bytes32 s,
            uint8 v
        )
    {
        require(_sig.length == 65, "siglngth");

        assembly {
            r := mload(add(_sig, 32))
            s := mload(add(_sig, 64))
            v := byte(0, mload(add(_sig, 96)))
        }
    }

    function verifySignature(
        string memory _messageOne,
        string memory _messageTwo,
        uint _numberOne,
        uint _numberTwo,
        bytes memory signature
    ) internal view returns (bool) {
        bytes32 _messageHash = getMessageHash(_messageOne, _messageTwo, _numberOne, _numberTwo, msg.sender);
        bytes32 _ethSignedMessageHash = getEthSignedMessageHash(_messageHash);
        return recoverSigner(_ethSignedMessageHash, signature) == verifySigner;
    }
}

// Dependency file: contracts/imports/Withdraw.sol


/*
*
* Withdraw Contract
* 
* Contract by Matt Casanova [Twitter: @DevGuyThings]
* 
* Withdraw funds from a contract
*
*/

// pragma solidity 0.8.9;

// import "@openzeppelin/contracts/access/Ownable.sol";

contract Withdraw is Ownable {
    function seeBalance() public view onlyOwner returns(uint)  {
        return address(this).balance;
    }

    function withdraw(address payable _to, uint _amount) public onlyOwner returns(bool)  {
        require(_amount <= address(this).balance, "insfnds");
        _to.transfer(_amount);
        return true;
    }
}

// Dependency file: contracts/imports/Group.sol


/*
*
* Group Contract
* 
* Contract by Matt Casanova [Twitter: @DevGuyThings]
* 
* To be used in conjuction with VerifySignature as a way to validate a signature generated off-chain
*
*/

// pragma solidity 0.8.9;

// import "@openzeppelin/contracts/access/Ownable.sol";

contract Group is Ownable {

    string public group = "init";

    event GroupUpdated(string _group);

    function setGroup(string memory _grp) public onlyOwner {
        group = _grp;
        emit GroupUpdated(_grp);
    }
}

// Dependency file: contracts/imports/ExternalAccount.sol


/*
*
* ExternalAccount Contract
* 
* Contract by Matt Casanova [Twitter: @DevGuyThings]
* 
* To be used to allow a single external address (likely another another contract) to interact with particular functions
*
*/

// pragma solidity 0.8.9;

// import "@openzeppelin/contracts/access/Ownable.sol";

contract ExternalAccount is Ownable {

    address public externalAccount;

    function setExternalAccount(address _addr) public onlyOwner {
        externalAccount = _addr;
    }

    modifier onlyExternalAccount() {
        require(externalAccount != address(0), "noext");
        require(msg.sender == externalAccount, "invacct");
        _;
    }
}

// Dependency file: @openzeppelin/contracts/token/ERC1155/IERC1155.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token 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 amount 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 `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `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 calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` 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 amounts,
        bytes calldata data
    ) external;
}


// Dependency file: @openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
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.
        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. 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);
}


// Dependency file: @openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 *
 * _Available since v3.1._
 */
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);
}


// Dependency file: @openzeppelin/contracts/token/ERC1155/ERC1155.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
// import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
// import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
// import "@openzeppelin/contracts/utils/Address.sol";
// import "@openzeppelin/contracts/utils/Context.sol";
// import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

/**
 * @dev Implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 *
 * _Available since v3.1._
 */
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
    using Address for address;

    // Mapping from token ID to account balances
    mapping(uint256 => mapping(address => uint256)) private _balances;

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

    /**
     * @dev See {_setURI}.
     */
    constructor(string memory uri_) {
        _setURI(uri_);
    }

    /**
     * @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 ||
            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 See {IERC1155-balanceOf}.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
        require(account != address(0), "ERC1155: balance query for the zero address");
        return _balances[id][account];
    }

    /**
     * @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)
    {
        require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");

        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 {
        require(_msgSender() != operator, "ERC1155: setting approval status for self");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_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 {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );
        _safeTransferFrom(from, to, id, amount, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: transfer caller is not owner nor approved"
        );
        _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.
     * - `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
    ) internal virtual {
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data);

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }
        _balances[id][to] += amount;

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

        _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
    }

    /**
     * @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 {
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

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

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
            _balances[id][to] += amount;
        }

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

        _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
    }

    /**
     * @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 of token type `id`, and assigns them to `account`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - If `account` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(
        address account,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(account != address(0), "ERC1155: mint to the zero address");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data);

        _balances[id][account] += amount;
        emit TransferSingle(operator, address(0), account, id, amount);

        _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _mintBatch(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; i++) {
            _balances[ids[i]][to] += amounts[i];
        }

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

        _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
    }

    /**
     * @dev Destroys `amount` tokens of token type `id` from `account`
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens of token type `id`.
     */
    function _burn(
        address account,
        uint256 id,
        uint256 amount
    ) internal virtual {
        require(account != address(0), "ERC1155: burn from the zero address");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), "");

        uint256 accountBalance = _balances[id][account];
        require(accountBalance >= amount, "ERC1155: burn amount exceeds balance");
        unchecked {
            _balances[id][account] = accountBalance - amount;
        }

        emit TransferSingle(operator, account, address(0), id, amount);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     */
    function _burnBatch(
        address account,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual {
        require(account != address(0), "ERC1155: burn from the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, account, address(0), ids, amounts, "");

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

            uint256 accountBalance = _balances[id][account];
            require(accountBalance >= amount, "ERC1155: burn amount exceeds balance");
            unchecked {
                _balances[id][account] = accountBalance - amount;
            }
        }

        emit TransferBatch(operator, account, address(0), ids, amounts);
    }

    /**
     * @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 `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 _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");
            }
        }
    }

    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");
            }
        }
    }

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

        return array;
    }
}


// Dependency file: @openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

/**
 * @dev Extension of {ERC1155} that allows token holders to destroy both their
 * own tokens and those that they have been approved to use.
 *
 * _Available since v3.1._
 */
abstract contract ERC1155Burnable is ERC1155 {
    function burn(
        address account,
        uint256 id,
        uint256 value
    ) public virtual {
        require(
            account == _msgSender() || isApprovedForAll(account, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );

        _burn(account, id, value);
    }

    function burnBatch(
        address account,
        uint256[] memory ids,
        uint256[] memory values
    ) public virtual {
        require(
            account == _msgSender() || isApprovedForAll(account, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );

        _burnBatch(account, ids, values);
    }
}


// Dependency file: @openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

/**
 * @dev Extension of ERC1155 that adds tracking of total supply per id.
 *
 * Useful for scenarios where Fungible and Non-fungible tokens have to be
 * clearly identified. Note: While a totalSupply of 1 might mean the
 * corresponding is an NFT, there is no guarantees that no other token with the
 * same id are not going to be minted.
 */
abstract contract ERC1155Supply is ERC1155 {
    mapping(uint256 => uint256) private _totalSupply;

    /**
     * @dev Total amount of tokens in with a given id.
     */
    function totalSupply(uint256 id) public view virtual returns (uint256) {
        return _totalSupply[id];
    }

    /**
     * @dev Indicates weither any token exist with a given id, or not.
     */
    function exists(uint256 id) public view virtual returns (bool) {
        return ERC1155Supply.totalSupply(id) > 0;
    }

    /**
     * @dev See {ERC1155-_mint}.
     */
    function _mint(
        address account,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual override {
        super._mint(account, id, amount, data);
        _totalSupply[id] += amount;
    }

    /**
     * @dev See {ERC1155-_mintBatch}.
     */
    function _mintBatch(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual override {
        super._mintBatch(to, ids, amounts, data);
        for (uint256 i = 0; i < ids.length; ++i) {
            _totalSupply[ids[i]] += amounts[i];
        }
    }

    /**
     * @dev See {ERC1155-_burn}.
     */
    function _burn(
        address account,
        uint256 id,
        uint256 amount
    ) internal virtual override {
        super._burn(account, id, amount);
        _totalSupply[id] -= amount;
    }

    /**
     * @dev See {ERC1155-_burnBatch}.
     */
    function _burnBatch(
        address account,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual override {
        super._burnBatch(account, ids, amounts);
        for (uint256 i = 0; i < ids.length; ++i) {
            _totalSupply[ids[i]] -= amounts[i];
        }
    }
}


// Dependency file: contracts/CabinetOfCuriosities.sol


/*
*
* Society of the Hourglass: Cabinet of Curiosities
* 
* Contract by Matt Casanova [Twitter: @DevGuyThings]
* 
* Website: https://www.societyofthehourglass.com/
* Mint Page: https://app.hashku.com/team/society-of-the-hourglass/cabinet-of-curiosities/mint
*
*/

// pragma solidity 0.8.9;

// import "contracts/imports/VerifySignature.sol";
// import "contracts/imports/Withdraw.sol";
// import "contracts/imports/Group.sol";
// import "contracts/imports/ExternalAccount.sol";
// import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
// import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";
// import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
// import "@openzeppelin/contracts/access/Ownable.sol";

contract CabinetOfCuriosities is 
    Ownable, 
    Withdraw, 
    Group, 
    VerifySignature, 
    ExternalAccount,
    ERC1155, 
    ERC1155Burnable
{
    mapping(uint256 => uint256) private _totalSupply;

    struct CabinetItem {
        uint256 price;
        uint256 amountMinted;
        uint256 amountAllowed;
        uint256 maxMintPerAddress;
        uint256 mainCollectionQty;
    }
    mapping(uint256 => CabinetItem) public items;

    /// @notice How many items someone can mint
    uint256 public maxMintEachAddress = 2;
    mapping(address => uint) public hasMinted;

    string private cabinetUri = "https://storage.hashku.com/api/soth/cabinet/{id}.json";

    uint256 constant private DUST = 0;
    uint256 constant private SCOPE = 1;
    uint256 constant private BOOK = 2;
    uint256 constant private BOT = 3;
    uint256 constant private POSTER = 4;
    uint256 constant private BOOK_CLOSED = 5;
    uint256 constant private BOT_ACTIVE = 6;

    uint256 public currentRaffleIndex = 11;

    mapping(uint256 => bool) public nigelWinners;

    constructor() ERC1155("https://storage.hashku.com/soth/cabinet/{id}.json") {
        // forget me dust
        items[DUST] = CabinetItem(60000000000000000, 0, 222, 2, 2);

        // pocket spectroscope
        items[SCOPE] = CabinetItem(120000000000000000, 0, 166, 2, 4);

        // book of epochs
        items[BOOK] = CabinetItem(170000000000000000, 0, 99, 2, 4);

        // autotranslator bot
        items[BOT] = CabinetItem(170000000000000000, 0, 99, 2, 4);

        // wanted poster of nigel
        items[POSTER] = CabinetItem(180000000000000000, 0, 99, 2, 4);

        // opened book of epochs
        items[BOOK_CLOSED] = CabinetItem(0, 0, 99, 2, 0);

        // activated autotranslator bot
        items[BOT_ACTIVE] = CabinetItem(0, 0, 99, 2, 0);

        // Raffle tickets will be IDs 11-99
    }

    /*
    * @notice Total supply of a given item
    */
    function totalSupply(uint256 id) public view returns (uint256) {
        return _totalSupply[id];
    }

    function _mint(
        address account,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal override {
        super._mint(account, id, amount, data);
        _totalSupply[id] += amount;
    }

    function _burn(
        address account,
        uint256 id,
        uint256 amount
    ) internal override {
        super._burn(account, id, amount);
        _totalSupply[id] -= amount;
    }

    /*
    * @notice Set overall quanitity a user is allowed to mint
    */
    function setMaxMintEachAddress(uint256 _amt) public onlyOwner {
        maxMintEachAddress = _amt;
    }

    /*
    * @notice Set a Nigel raffle ticket as a winner
    */
    function setNigelWinner(uint256 _id) public onlyOwner {
        nigelWinners[_id] = true;
    }

    /*
    * @notice Allow updating the item data
    */
    function setItem( uint256 _id, uint256 _price, uint256 _amountAllowed, uint256 _maxMintPerAddress, uint256 _mainCollectionQty ) public onlyOwner {
        items[_id].price = _price;
        items[_id].amountAllowed = _amountAllowed;
        items[_id].maxMintPerAddress = _maxMintPerAddress;
        items[_id].mainCollectionQty = _mainCollectionQty;
    }

    function uri(uint256) public view override returns (string memory) {
        return cabinetUri;
    }
    
    function setURI(string memory _newuri) public onlyOwner {
        cabinetUri = _newuri;
    }

    /*
    * @notice Shop for a single item of varyiable quantity
    */
    function shop( uint256 _id, uint256 _qty, bytes memory _signature ) public payable {
        // check signature - will be provided by Hashku
        require(verifySignature("SHOP", group, _id, _qty, _signature), "invsig");
        require(_id < 5, "invitm");
        require(_qty * items[_id].price == msg.value, "incfnds");

        mintInternal(msg.sender, _id, _qty);
    }

    /*
    * @notice Shop for more than a single item
    */
    function shopMultiple( uint256[] memory _ids, uint256[] memory _qtys, bytes memory _signature ) public payable {
        // check signature - will be provided by Hashku
        require(verifySignature("SHOP", group, _ids[0], _qtys[0], _signature), "invsig");
        require(_ids.length == _qtys.length, "idqtymm");
        require(_ids.length < 6, "maxitms");

        uint256 _totalPrice;
        for (uint256 _i = 0; _i < _ids.length; _i++) {
            require(_ids[_i] < 5, "invitm");
            _totalPrice += items[_ids[_i]].price * _qtys[_i];
        }

        require(_totalPrice == msg.value, "incfnds");

        for (uint256 _i = 0; _i < _ids.length; _i++) {
            mintInternal(msg.sender, _ids[_i], _qtys[_i]);
        }
    }

    /*
    * @notice Mint an item, used by other functions only
    */
    function mintInternal(address _to, uint256 _id, uint256 _qty) internal {
        require(hasMinted[_to] + _qty <= maxMintEachAddress, "mintmax");
        require(items[_id].amountMinted + _qty <= items[_id].amountAllowed, "itmunv");
        require(_qty + balanceOf(_to, _id) <= items[_id].maxMintPerAddress, "itmmax");

        hasMinted[_to] += _qty;
        items[_id].amountMinted += _qty;
        _mint(_to, _id, _qty, "");
    }

    /*
    * @notice Send tokens to an address (to be used for rewarding community members and partners)
    */
    function send(address _to, uint256[] memory _ids, uint256[] memory _qtys) public onlyOwner {
        require(_ids.length == _qtys.length, "idqtymm");
        require(_ids.length < 6, "maxitms");

        for (uint256 _i = 0; _i < _ids.length; _i++) {
            require(_ids[_i] < 5, "invitm");
        }

        for (uint256 _i = 0; _i < _ids.length; _i++) {
            mintInternal(_to, _ids[_i], _qtys[_i]);
        }
    }

    /*
    * @notice Mint BOOK_CLOSED or BOT_ACTIVE from redemption contract
    */
    function mintExternal(address _to, uint256 _id, uint256 _qty) external onlyExternalAccount {
        require(_id > 4, "invitm");
        require(_id < 7, "invitm");
        items[_id].amountMinted += _qty;
        _mint(_to, _id, _qty, "");
    }

    /*
    * @notice Mint Nigel raffle ticket (IDs 11+)
    */
    function mintNigelRaffle(address _to, uint256 _qty) external onlyExternalAccount {
        for (uint256 _i = 0; _i < _qty; _i++) {
            _mint(_to, currentRaffleIndex, 1, "");
            currentRaffleIndex += 1;
        }
    }

    /*
    * @notice Burn token from redemption account
    */
    function burnExternal(address _to, uint256 _id, uint256 _qty) external onlyExternalAccount {
        _burn(_to, _id, _qty);
    }

    /*
    * @notice Shortcut for retrieving number of main collection NFTs are redemeed from a Cabinet item
    */
    function itemMainCollectionQuantity(uint256 _id) public view returns (uint256) {
        return items[_id].mainCollectionQty;
    }

    function burn(
        address _account,
        uint256 _id,
        uint256 _value
    ) override public virtual onlyOwner {}

    function burnBatch(
        address _account,
        uint256[] memory _ids,
        uint256[] memory _values
    ) override public virtual onlyOwner {}
}


// Dependency file: @openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol


// pragma solidity ^0.8.0;

// import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";

/**
 * @dev Implementation of the {IERC721Receiver} interface.
 *
 * Accepts all token transfers.
 * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
 */
contract ERC721Holder is IERC721Receiver {
    /**
     * @dev See {IERC721Receiver-onERC721Received}.
     *
     * Always returns `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address,
        address,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC721Received.selector;
    }
}


// Root file: contracts/SocietyOfTheHourglass.sol

pragma solidity 0.8.9;

/*
*
* Society of the Hourglass: Main Collection + Cabinet of Curiosities Redemption
* 
* Contract by Matt Casanova [Twitter: @DevGuyThings]
* 
* Website: https://www.societyofthehourglass.com/
* Mint Page: https://app.hashku.com/team/society-of-the-hourglass/main/mint
*
*/

// import "contracts/Hashku.sol";
// import "contracts/CabinetOfCuriosities.sol";
// import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
// import "@openzeppelin/contracts/utils/Strings.sol";

contract SocietyOfTheHourglass is Hashku, ERC721Holder {
    using Strings for uint256;

    // total main collection tokens based on 2022-01-01 cabinet items; will decrease as cabinet items are redeemed
    uint256 public reservedFromCabinet = 642;

    // mapping of which tokens have a bot
    mapping(uint256 => bool) public hasBot;

    // mappig of which tokens are in the book
    mapping(uint256 => bool) public inBook;

    // track which nigel token will mint next
    uint256 public nextNigelIndex;

    // how many nigels total
    uint256 constant private nigelsAvailable = 10;

    constructor() Hashku(
        "Society of the Hourglass", 
        "SOTH", 
        "https://storage.hashku.com/api/soth/main/", 
        "SOTH", 
        8888, 
        20, 
        30, 
        70000000000000000, 
        5, 
        0xED0998a1489Ab5cF1900f546f620aB67Af19915B
    ) {
        // on deploy, mint the first 10 tokens to the contract
        // these first ten tokens are nigels
        for (uint256 i = 0; i < nigelsAvailable; i++) {
            mint(address(this));
        }
    }

    // set however many tokens should be reserved for cabinet redemption
    function setReservedFromCabinet(uint256 _amt) public onlyOwner {
        require(nextToken() + _amt <= maxTokens, "too_many");
        reservedFromCabinet = _amt;
    }

    // owner can ONLY decrease the total number of available tokens
    function decreaseMaxTokens(uint256 _amount) external override onlyOwner {
        require(_amount < maxTokens, "only_decrease");
        require(_amount > reservedFromCabinet + nextToken(), "cabinet_reserved");
        maxTokens = _amount;
    }

    // internal function for transferring a nigel
    function transferNigel(address _to) internal {
        // nigels will be 0-9, nigelsAvailable will be 10
        require(nextNigelIndex + 1 < nigelsAvailable, "none_available");
        uint256 nigelIdToClaim = nextNigelIndex;
        nextNigelIndex += 1;
        _safeTransfer(address(this), _to, nigelIdToClaim, "");
        delete nigelIdToClaim;
    }

    // internal function for setting bot on a token
    function setHasBot(uint256 _tokenId) internal {
        require(!hasBot[_tokenId], "already_has_bot");
        hasBot[_tokenId] = true;
    }

    // internal function for marking a token in the book
    function setIsInBook(uint256 _tokenId) internal {
        require(!inBook[_tokenId], "already_has_bot");
        inBook[_tokenId] = true;
    }

    // once final tokens are set and we know all tokens to be in book, will call this to update the contract
    function setIsInBookMultiple(uint256[] calldata _tokenIds) external onlyOwner {
        for (uint256 i = 0; i < _tokenIds.length; i++) {
            setIsInBook(_tokenIds[i]);
        }
    }

    // returns uri with data for book and bot where appropriate
    function tokenURI(uint256 _tokenId) public view override returns (string memory) {
        require(_exists(_tokenId), "no_token");

        string memory append = ".json?var=1";
        string memory addBot = "";
        if (hasBot[_tokenId]) {
            addBot = "&bot=yes";
        }
        string memory addBook = "";
        if (inBook[_tokenId]) {
            addBook = "&book=yes";
        }

        return bytes(baseTokenURI).length > 0 ? string(abi.encodePacked(baseTokenURI, _tokenId.toString(), append, addBot, addBook)) : "";
    }

    // buy NFTs - version without signature required for public mint
    function shop(uint256 _amount) external override payable {
        require(nextToken() + _amount + reservedFromCabinet <= maxTokens, "sold_out");
        require(_amount <= maxMintPerTransaction, "max_mintable");
        require(!isClosed, "is_closed");
        require(isPublic, "not_public");
        require(price * _amount == msg.value, "incorrect_funds");
        for (uint256 i = 0; i < _amount; i++) {
            mint(_msgSender());
        }
    }

    // buy NFTs - signature required from Hashku for presale
    function shop(uint256 _amount, bytes memory _signature) external override payable {
        require(nextToken() + _amount + reservedFromCabinet <= maxTokens, "sold_out");
        require(tokensMinted[_msgSender()] + _amount <= maxMintPerAddress, "max_minted");
        require(!isClosed, "is_closed");
        require(verifySignature(_signature), "invalid_signature");
        require(price * _amount == msg.value, "incorrect_funds");

        tokensMinted[_msgSender()] += _amount;
        for (uint256 i = 0; i < _amount; i++) {
            mint(_msgSender());
        }
    }

    // owner sends NFTs to addresses
    function send(address[] calldata _addresses, uint256[] calldata _amounts) external override onlyOwner {
        require(_addresses.length == _amounts.length, "amount_mismatch");

        uint256 total;
        for (uint256 t = 0; t < _amounts.length; t++) {
            total += _amounts[t];
        }

        require(nextToken() + total + reservedFromCabinet <= maxTokens, "sold_out");

        delete total;

        for (uint256 i = 0; i < _addresses.length; i++) {
            for (uint256 a = 0; a < _amounts[i]; a++) {
                mint(_addresses[i]);
            }
        }
    }

    // cabinet collection address
    CabinetOfCuriosities public externalAccount;

    // redemption of initial cabinet items allowed when true
    bool public redemptionOpen;

    // redemption of secondary cabinet items allowed when true
    bool public secondRedemptionOpen;

    modifier cabinetMustBeSet() {
        require(address(externalAccount) != address(0), "no_cabinet");
        _;
    }

    // open or close initial cabinet item redemption
    function setRedemptionOpen(bool _open) public onlyOwner {
        redemptionOpen = _open;
    }

    // open or close secondary cabinet item redemption
    function setSecondRedemptionOpen(bool _open) public onlyOwner {
        secondRedemptionOpen = _open;
    }

    // set the cabinet account
    function setExternalAccount(address _contract) public onlyOwner {
        externalAccount = CabinetOfCuriosities(_contract);
    }

    // external function to mint Nigel raffle tickets in case we have external awards or later uses for raffle tickets
    function mintNigelRaffle(address _to, uint256 _qty) external onlyOwner cabinetMustBeSet {
        externalAccount.mintNigelRaffle(_to, _qty);
    }

    // redeem a winning nigel raffle ticket from the cabinet
    function useNigelTicket(uint256 _id) public cabinetMustBeSet {
        require(secondRedemptionOpen, "not_open");
        require(externalAccount.nigelWinners(_id), "not_winner");
        require(externalAccount.balanceOf(msg.sender, _id) >= 1, "not_enough");

        // burn nigel ticket
        externalAccount.burnExternal(msg.sender, _id, 1);

        // mint a nigel from the main collection
        transferNigel(msg.sender);
    }

    // check that the msg sender is the owner of an array of tokens
    function validateOwner(uint[] calldata _tokenIds) internal view returns (bool) {
        for (uint256 _i = 0; _i < _tokenIds.length; _i++) {
            // does the user own the tokenIds
            require(ownerOf(_tokenIds[_i]) == msg.sender, "not_owner");
        }

        return true;
    }

    // assign bots to main collection tokens
    function useBot(uint[] calldata _tokenIds) public cabinetMustBeSet {
        require(secondRedemptionOpen, "not_open");
        require(externalAccount.balanceOf(msg.sender, 6) >= _tokenIds.length, "no_item");
        validateOwner(_tokenIds);

        externalAccount.burnExternal(msg.sender, 6, _tokenIds.length);

        for (uint256 _i = 0; _i < _tokenIds.length; _i++) {
            setHasBot(_tokenIds[_i]);
        }
    }

    // assign books to main collection tokens
    function useBook(uint[] calldata _tokenIds) public cabinetMustBeSet {
        require(secondRedemptionOpen, "not_open");
        require(externalAccount.balanceOf(msg.sender, 5) >= _tokenIds.length, "no_item");
        validateOwner(_tokenIds);

        externalAccount.burnExternal(msg.sender, 5, _tokenIds.length);

        for (uint256 _i = 0; _i < _tokenIds.length; _i++) {
            setIsInBook(_tokenIds[_i]);
        }
    }

    // redeem items from the cabinet of curiosities
    function redeem(uint[] calldata _itemIds, uint[] calldata _itemQtys) public cabinetMustBeSet {
        require(redemptionOpen, "not_open");
        require(_itemIds.length > 0, "no_items");
        require(_itemIds.length == _itemQtys.length, "length_mismatch");
        require(_itemIds.length < 6, "invalid_items");

        for (uint256 _i = 0; _i < _itemIds.length; _i++) {
            require(_itemQtys[_i] > 0, "quantity_zero");
            // does the user own enough tokenIds
            require(externalAccount.balanceOf(msg.sender, _itemIds[_i]) >= _itemQtys[_i], "no_item");
            require(_itemIds[_i] < 5, "invalid_item");
        }

        uint256 _qtyMintMain;
        for (uint256 _i = 0; _i < _itemIds.length; _i++) {
            // burn the number of tokens by id
            externalAccount.burnExternal(msg.sender, _itemIds[_i], _itemQtys[_i]);

            // each token gets at least 1 from main collection
            _qtyMintMain += externalAccount.itemMainCollectionQuantity(_itemIds[_i]) * _itemQtys[_i];

            // book, bot, and poster get an additional item minted
            if (_itemIds[_i] == 2) {
                externalAccount.mintExternal(msg.sender, 5, _itemQtys[_i]);
            } else if (_itemIds[_i] == 3) {
                externalAccount.mintExternal(msg.sender, 6, _itemQtys[_i]);
            } else if (_itemIds[_i] == 4) {
                externalAccount.mintNigelRaffle(msg.sender, _itemQtys[_i]);
            }
        }

        reservedFromCabinet -= _qtyMintMain;

        // finally mint all the correct qty
        for (uint256 i = 0; i < _qtyMintMain; i++) {
            mint(msg.sender);
        }
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_type","type":"string"}],"name":"ContractUpdated","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":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"decreaseMaxTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eligible","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"externalAccount","outputs":[{"internalType":"contract CabinetOfCuriosities","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"group","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hasBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"inBook","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isClosed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPublic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"key","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintPerAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintPerTransaction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_qty","type":"uint256"}],"name":"mintNigelRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextNigelIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxyRegistryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_itemQtys","type":"uint256[]"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redemptionOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reservedFromCabinet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"royaltyPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"secondRedemptionOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seeBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"send","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":"_baseTokenURI","type":"string"}],"name":"setBaseUri","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"setExternalAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_group","type":"string"}],"name":"setGroup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_closed","type":"bool"}],"name":"setIsClosed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"setIsInBookMultiple","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_public","type":"bool"}],"name":"setIsPublic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_key","type":"string"}],"name":"setKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setMaxMintPerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setMaxMintPerTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_proxy","type":"address"}],"name":"setProxyRegistryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_open","type":"bool"}],"name":"setRedemptionOpen","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amt","type":"uint256"}],"name":"setReservedFromCabinet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setRoyaltyPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_open","type":"bool"}],"name":"setSecondRedemptionOpen","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_verifySigner","type":"address"}],"name":"setVerifySigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setWithdrawalAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"shop","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"shop","outputs":[],"stateMutability":"payable","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":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokensMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"useBook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"useBot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"useNigelTicket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"verifySigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c06040526004608081905263053484f560e41b60a09081526200002791600991906200060c565b50604080518082019091526004808252631a5b9a5d60e21b60209092019182526200005591600a916200060c565b506102826015553480156200006957600080fd5b506040518060400160405280601881526020017f536f6369657479206f662074686520486f7572676c6173730000000000000000815250604051806040016040528060048152602001630a69ea8960e31b8152506040518060600160405280602981526020016200667f602991396040805180820190915260048152630a69ea8960e31b60208201526122b86014601e66f8b0a10e470000600573ed0998a1489ab5cf1900f546f620ab67af19915b898962000125336200021a565b81516200013a9060019060208501906200060c565b508051620001509060029060208401906200060c565b5050885162000168915060089060208b01906200060c565b5086516200017e9060099060208a01906200060c565b50600d869055600b859055600c849055600e8390556013829055601180546001600160a01b0319166001600160a01b038316179055620001bb3390565b601280546001600160a01b0319166001600160a01b0392909216919091179055506000985050505050505050505b600a8110156200021357620001fe306200026a565b806200020a81620006c8565b915050620001e9565b50620007ec565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6200028c81620002866007620002a660201b620040ca1760201c565b620002aa565b620002a36007620002d060201b620040ce1760201c565b50565b5490565b620002cc828260405180602001604052806000815250620002d960201b60201c565b5050565b80546001019055565b620002e5838362000355565b620002f460008484846200049d565b620003505760405162461bcd60e51b815260206004820152603260248201526000805160206200665f83398151915260448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b60648201526084015b60405180910390fd5b505050565b6001600160a01b038216620003ad5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640162000347565b6000818152600360205260409020546001600160a01b031615620004145760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640162000347565b6001600160a01b03821660009081526004602052604081208054600192906200043f908490620006e6565b909155505060008181526003602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000620004be846001600160a01b03166200060660201b620040d71760201c565b15620005fa57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290620004f890339089908890889060040162000701565b602060405180830381600087803b1580156200051357600080fd5b505af192505050801562000546575060408051601f3d908101601f1916820190925262000543918101906200077c565b60015b620005df573d80801562000577576040519150601f19603f3d011682016040523d82523d6000602084013e6200057c565b606091505b508051620005d75760405162461bcd60e51b815260206004820152603260248201526000805160206200665f83398151915260448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606482015260840162000347565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050620005fe565b5060015b949350505050565b3b151590565b8280546200061a90620007af565b90600052602060002090601f0160209004810192826200063e576000855562000689565b82601f106200065957805160ff191683800117855562000689565b8280016001018555821562000689579182015b82811115620006895782518255916020019190600101906200066c565b50620006979291506200069b565b5090565b5b808211156200069757600081556001016200069c565b634e487b7160e01b600052601160045260246000fd5b6000600019821415620006df57620006df620006b2565b5060010190565b60008219821115620006fc57620006fc620006b2565b500190565b600060018060a01b038087168352602081871681850152856040850152608060608501528451915081608085015260005b82811015620007505785810182015185820160a00152810162000732565b828111156200076357600060a084870101525b5050601f01601f19169190910160a00195945050505050565b6000602082840312156200078f57600080fd5b81516001600160e01b031981168114620007a857600080fd5b9392505050565b600181811c90821680620007c457607f821691505b60208210811415620007e657634e487b7160e01b600052602260045260246000fd5b50919050565b615e6380620007fc6000396000f3fe60806040526004361061044a5760003560e01c80638edb25a011610243578063d26ea6c011610143578063e8c61831116100bb578063f3fef3a31161008a578063f75451f81161006f578063f75451f814610cfa578063fdab3b3f14610d1a578063fee99fb614610d3a57600080fd5b8063f3fef3a314610cba578063f71b40ff14610cda57600080fd5b8063e8c6183114610c20578063e985e9c514610c4d578063f2bcd02214610c6d578063f2fde38b14610c9a57600080fd5b8063d870155411610112578063dc9a1535116100f7578063dc9a153514610bd0578063e0d11a4714610bea578063e831574214610c0a57600080fd5b8063d870155414610baa578063da69c08314610bbd57600080fd5b8063d26ea6c014610b40578063d547cfb714610b60578063d6a2a4bc14610b75578063d832d92f14610b9557600080fd5b8063a0bcfc7f116101d6578063b88d4fde116101a5578063c87b56dd1161018a578063c87b56dd14610ad3578063c97b973014610af3578063cd7c032614610b1357600080fd5b8063b88d4fde14610a94578063c2b6b58c14610ab457600080fd5b8063a0bcfc7f14610a14578063a22cb46514610a34578063a645ff5f14610a54578063af42d10614610a7457600080fd5b806395d89b411161021257806395d89b41146109b35780639a4fc640146109c85780639f67756d146109e8578063a035b1fe146109fe57600080fd5b80638edb25a01461093e5780639149fe401461095e57806391b7f5ed1461097e5780639499ac541461099e57600080fd5b80633943380c1161034e5780635cffabb1116102e1578063715018a6116102b0578063800b434411610295578063800b4344146108c1578063835b57b9146108f35780638da5cb5b1461091357600080fd5b8063715018a61461088c5780637c39e0e0146108a157600080fd5b80635cffabb1146108095780636352211e1461081f5780636d08557a1461083f57806370a082311461086c57600080fd5b806349668b4a1161031d57806349668b4a146107865780635444d103146107a657806354610481146107c6578063572849c4146107f357600080fd5b80633943380c1461070957806342842e0e1461071e578063429a1bb01461073e578063434735ff1461075357600080fd5b80631b2a1e32116103e157806323b872dd116103b05780632a55205a116103955780632a55205a1461067d5780632ca51e22146106c95780632e6cebe5146106e957600080fd5b806323b872dd1461064857806329e7ef2d1461066857600080fd5b80631b2a1e32146105c25780631e14d44b146105d85780631f9ba96b146105f857806321b8092e1461062857600080fd5b8063081812fc1161041d578063081812fc146104ec578063095ea7b3146105315780630f2abec014610551578063150b7a021461057157600080fd5b806301f569971461044f57806301ffc9a71461047857806306fdde03146104a857806307953da1146104ca575b600080fd5b34801561045b57600080fd5b50610465600c5481565b6040519081526020015b60405180910390f35b34801561048457600080fd5b506104986104933660046154b8565b610d6a565b604051901515815260200161046f565b3480156104b457600080fd5b506104bd610dc6565b60405161046f919061554b565b3480156104d657600080fd5b506104ea6104e536600461556c565b610e58565b005b3480156104f857600080fd5b5061050c610507366004615589565b610f0f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161046f565b34801561053d57600080fd5b506104ea61054c3660046155c4565b610fcf565b34801561055d57600080fd5b506104ea61056c366004615635565b611128565b34801561057d57600080fd5b5061059161058c36600461575a565b6113c6565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161046f565b3480156105ce57600080fd5b5061046560185481565b3480156105e457600080fd5b506104ea6105f3366004615589565b6113f0565b34801561060457600080fd5b50610498610613366004615589565b60176020526000908152604090205460ff1681565b34801561063457600080fd5b506104ea6106433660046157c6565b61145c565b34801561065457600080fd5b506104ea6106633660046157e3565b61156f565b34801561067457600080fd5b506104bd6115f6565b34801561068957600080fd5b5061069d610698366004615824565b611684565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161046f565b3480156106d557600080fd5b506104ea6106e4366004615846565b61171a565b3480156106f557600080fd5b506104ea610704366004615589565b611f45565b34801561071557600080fd5b506104bd611fb1565b34801561072a57600080fd5b506104ea6107393660046157e3565b611fbe565b34801561074a57600080fd5b50610465611fd9565b34801561075f57600080fd5b50601954610498907501000000000000000000000000000000000000000000900460ff1681565b34801561079257600080fd5b506104ea6107a136600461556c565b6120ad565b3480156107b257600080fd5b506104ea6107c1366004615635565b6121b1565b3480156107d257600080fd5b506104656107e13660046157c6565b60106020526000908152604090205481565b3480156107ff57600080fd5b50610465600b5481565b34801561081557600080fd5b5061046560155481565b34801561082b57600080fd5b5061050c61083a366004615589565b61244f565b34801561084b57600080fd5b5060195461050c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561087857600080fd5b506104656108873660046157c6565b6124e7565b34801561089857600080fd5b506104ea61259b565b3480156108ad57600080fd5b506104ea6108bc366004615589565b61260e565b3480156108cd57600080fd5b506019546104989074010000000000000000000000000000000000000000900460ff1681565b3480156108ff57600080fd5b506104ea61090e366004615635565b61295e565b34801561091f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661050c565b34801561094a57600080fd5b506104ea610959366004615589565b6129f7565b34801561096a57600080fd5b506104ea6109793660046155c4565b612b17565b34801561098a57600080fd5b506104ea610999366004615589565b612c6b565b3480156109aa57600080fd5b50610465612cd7565b3480156109bf57600080fd5b506104bd612ce7565b3480156109d457600080fd5b506104ea6109e3366004615589565b612cf6565b3480156109f457600080fd5b5061046560135481565b348015610a0a57600080fd5b50610465600e5481565b348015610a2057600080fd5b506104ea610a2f3660046158b2565b612d62565b348015610a4057600080fd5b506104ea610a4f366004615924565b612dd5565b348015610a6057600080fd5b506104ea610a6f366004615846565b612ed2565b348015610a8057600080fd5b506104ea610a8f3660046158b2565b6130c2565b348015610aa057600080fd5b506104ea610aaf36600461575a565b613135565b348015610ac057600080fd5b50600f5461049890610100900460ff1681565b348015610adf57600080fd5b506104bd610aee366004615589565b6131c3565b348015610aff57600080fd5b506104ea610b0e36600461595d565b613388565b348015610b1f57600080fd5b5060145461050c9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b4c57600080fd5b506104ea610b5b3660046157c6565b613462565b348015610b6c57600080fd5b506104bd613510565b348015610b8157600080fd5b506104ea610b9036600461556c565b61351d565b348015610ba157600080fd5b506104986135ce565b6104ea610bb83660046159a6565b6135f1565b6104ea610bcb366004615589565b613822565b348015610bdc57600080fd5b50600f546104989060ff1681565b348015610bf657600080fd5b506104ea610c053660046157c6565b613a15565b348015610c1657600080fd5b50610465600d5481565b348015610c2c57600080fd5b5060125461050c9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610c5957600080fd5b50610498610c683660046159ed565b613ac3565b348015610c7957600080fd5b5060115461050c9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610ca657600080fd5b506104ea610cb53660046157c6565b613bf2565b348015610cc657600080fd5b50610498610cd53660046155c4565b613ceb565b348015610ce657600080fd5b506104ea610cf5366004615589565b613e57565b348015610d0657600080fd5b506104ea610d153660046157c6565b613f27565b348015610d2657600080fd5b506104ea610d3536600461556c565b613fd5565b348015610d4657600080fd5b50610498610d55366004615589565b60166020526000908152604090205460ff1681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a000000000000000000000000000000000000000000000000000000001480610dc05750610dc0826140dd565b92915050565b606060018054610dd590615a1b565b80601f0160208091040260200160405190810160405280929190818152602001828054610e0190615a1b565b8015610e4e5780601f10610e2357610100808354040283529160200191610e4e565b820191906000526020600020905b815481529060010190602001808311610e3157829003601f168201915b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ec45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b601980549115157501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60008181526003602052604081205473ffffffffffffffffffffffffffffffffffffffff16610fa65760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e00000000000000000000000000000000000000006064820152608401610ebb565b5060009081526005602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6000610fda8261244f565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561107e5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610ebb565b3373ffffffffffffffffffffffffffffffffffffffff821614806110a757506110a78133613ac3565b6111195760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610ebb565b61112383836141c0565b505050565b60195473ffffffffffffffffffffffffffffffffffffffff1661118d5760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b6019547501000000000000000000000000000000000000000000900460ff166111f85760405162461bcd60e51b815260206004820152600860248201527f6e6f745f6f70656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517efdd58e00000000000000000000000000000000000000000000000000000000815233600482015260066024820152829173ffffffffffffffffffffffffffffffffffffffff169062fdd58e9060440160206040518083038186803b15801561126657600080fd5b505afa15801561127a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129e9190615a6f565b10156112ec5760405162461bcd60e51b815260206004820152600760248201527f6e6f5f6974656d000000000000000000000000000000000000000000000000006044820152606401610ebb565b6112f68282614260565b506019546040517f59e874ef000000000000000000000000000000000000000000000000000000008152336004820152600660248201526044810183905273ffffffffffffffffffffffffffffffffffffffff909116906359e874ef90606401600060405180830381600087803b15801561137057600080fd5b505af1158015611384573d6000803e3d6000fd5b5050505060005b81811015611123576113b48383838181106113a8576113a8615a88565b90506020020135614303565b806113be81615ae6565b91505061138b565b7f150b7a02000000000000000000000000000000000000000000000000000000005b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146114575760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600b55565b60115473ffffffffffffffffffffffffffffffffffffffff166114c15760405162461bcd60e51b815260206004820152600e60248201527f6e6f5f7769746864726177616c730000000000000000000000000000000000006044820152606401610ebb565b60115473ffffffffffffffffffffffffffffffffffffffff1633146115285760405162461bcd60e51b815260206004820152600b60248201527f6e6f745f616c6c6f7765640000000000000000000000000000000000000000006044820152606401610ebb565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611579338261439b565b6115eb5760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610ebb565b6111238383836144bc565b600a805461160390615a1b565b80601f016020809104026020016040519081016040528092919081815260200182805461162f90615a1b565b801561167c5780601f106116515761010080835404028352916020019161167c565b820191906000526020600020905b81548152906001019060200180831161165f57829003601f168201915b505050505081565b600082815260036020526040812054819073ffffffffffffffffffffffffffffffffffffffff166116f75760405162461bcd60e51b815260206004820152600860248201527f6e6f5f746f6b656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b3061170e611707856013546146ef565b60646146fb565b915091505b9250929050565b60195473ffffffffffffffffffffffffffffffffffffffff1661177f5760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b60195474010000000000000000000000000000000000000000900460ff166117e95760405162461bcd60e51b815260206004820152600860248201527f6e6f745f6f70656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b826118365760405162461bcd60e51b815260206004820152600860248201527f6e6f5f6974656d730000000000000000000000000000000000000000000000006044820152606401610ebb565b8281146118855760405162461bcd60e51b815260206004820152600f60248201527f6c656e6774685f6d69736d6174636800000000000000000000000000000000006044820152606401610ebb565b600683106118d55760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69645f6974656d73000000000000000000000000000000000000006044820152606401610ebb565b60005b83811015611b095760008383838181106118f4576118f4615a88565b90506020020135116119485760405162461bcd60e51b815260206004820152600d60248201527f7175616e746974795f7a65726f000000000000000000000000000000000000006044820152606401610ebb565b82828281811061195a5761195a615a88565b601954602090910292909201359173ffffffffffffffffffffffffffffffffffffffff16905062fdd58e3388888681811061199757611997615a88565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815273ffffffffffffffffffffffffffffffffffffffff9094166004850152602002919091013560248301525060440160206040518083038186803b158015611a0957600080fd5b505afa158015611a1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a419190615a6f565b1015611a8f5760405162461bcd60e51b815260206004820152600760248201527f6e6f5f6974656d000000000000000000000000000000000000000000000000006044820152606401610ebb565b6005858583818110611aa357611aa3615a88565b9050602002013510611af75760405162461bcd60e51b815260206004820152600c60248201527f696e76616c69645f6974656d00000000000000000000000000000000000000006044820152606401610ebb565b80611b0181615ae6565b9150506118d8565b506000805b84811015611efe5760195473ffffffffffffffffffffffffffffffffffffffff166359e874ef33888885818110611b4757611b47615a88565b90506020020135878786818110611b6057611b60615a88565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff9095166004860152602485019390935250602090910201356044820152606401600060405180830381600087803b158015611bdb57600080fd5b505af1158015611bef573d6000803e3d6000fd5b50505050838382818110611c0557611c05615a88565b601954602090910292909201359173ffffffffffffffffffffffffffffffffffffffff169050639d354516888885818110611c4257611c42615a88565b905060200201356040518263ffffffff1660e01b8152600401611c6791815260200190565b60206040518083038186803b158015611c7f57600080fd5b505afa158015611c93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb79190615a6f565b611cc19190615b1f565b611ccb9083615b5c565b9150858582818110611cdf57611cdf615a88565b9050602002013560021415611db95760195473ffffffffffffffffffffffffffffffffffffffff1663e7228e61336005878786818110611d2157611d21615a88565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff9095166004860152602485019390935250602090910201356044820152606401600060405180830381600087803b158015611d9c57600080fd5b505af1158015611db0573d6000803e3d6000fd5b50505050611eec565b858582818110611dcb57611dcb615a88565b9050602002013560031415611e0d5760195473ffffffffffffffffffffffffffffffffffffffff1663e7228e61336006878786818110611d2157611d21615a88565b858582818110611e1f57611e1f615a88565b9050602002013560041415611eec5760195473ffffffffffffffffffffffffffffffffffffffff16639149fe4033868685818110611e5f57611e5f615a88565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815273ffffffffffffffffffffffffffffffffffffffff90941660048501526020029190910135602483015250604401600060405180830381600087803b158015611ed357600080fd5b505af1158015611ee7573d6000803e3d6000fd5b505050505b80611ef681615ae6565b915050611b0e565b508060156000828254611f119190615b74565b90915550600090505b81811015611f3d57611f2b33614707565b80611f3581615ae6565b915050611f1a565b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611fac5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600c55565b6009805461160390615a1b565b61112383838360405180602001604052806000815250613135565b60115460009073ffffffffffffffffffffffffffffffffffffffff166120415760405162461bcd60e51b815260206004820152600e60248201527f6e6f5f7769746864726177616c730000000000000000000000000000000000006044820152606401610ebb565b60115473ffffffffffffffffffffffffffffffffffffffff1633146120a85760405162461bcd60e51b815260206004820152600b60248201527f6e6f745f616c6c6f7765640000000000000000000000000000000000000000006044820152606401610ebb565b504790565b60005473ffffffffffffffffffffffffffffffffffffffff1633146121145760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600f8054821515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790556040517f38b9241ba197630c4329259c93d6a140b00cbe738808b738f460c5571d02b442906121a69060208082526008908201527f6973436c6f736564000000000000000000000000000000000000000000000000604082015260600190565b60405180910390a150565b60195473ffffffffffffffffffffffffffffffffffffffff166122165760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b6019547501000000000000000000000000000000000000000000900460ff166122815760405162461bcd60e51b815260206004820152600860248201527f6e6f745f6f70656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517efdd58e00000000000000000000000000000000000000000000000000000000815233600482015260056024820152829173ffffffffffffffffffffffffffffffffffffffff169062fdd58e9060440160206040518083038186803b1580156122ef57600080fd5b505afa158015612303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123279190615a6f565b10156123755760405162461bcd60e51b815260206004820152600760248201527f6e6f5f6974656d000000000000000000000000000000000000000000000000006044820152606401610ebb565b61237f8282614260565b506019546040517f59e874ef000000000000000000000000000000000000000000000000000000008152336004820152600560248201526044810183905273ffffffffffffffffffffffffffffffffffffffff909116906359e874ef90606401600060405180830381600087803b1580156123f957600080fd5b505af115801561240d573d6000803e3d6000fd5b5050505060005b818110156111235761243d83838381811061243157612431615a88565b90506020020135614727565b8061244781615ae6565b915050612414565b60008181526003602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610dc05760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201527f656e7420746f6b656e00000000000000000000000000000000000000000000006064820152608401610ebb565b600073ffffffffffffffffffffffffffffffffffffffff82166125725760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610ebb565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205490565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126025760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b61260c60006147bf565b565b60195473ffffffffffffffffffffffffffffffffffffffff166126735760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b6019547501000000000000000000000000000000000000000000900460ff166126de5760405162461bcd60e51b815260206004820152600860248201527f6e6f745f6f70656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517f4496a4530000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff90911690634496a4539060240160206040518083038186803b15801561274857600080fd5b505afa15801561275c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127809190615b8b565b6127cc5760405162461bcd60e51b815260206004820152600a60248201527f6e6f745f77696e6e6572000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517efdd58e0000000000000000000000000000000000000000000000000000000081523360048201526024810183905260019173ffffffffffffffffffffffffffffffffffffffff169062fdd58e9060440160206040518083038186803b15801561283b57600080fd5b505afa15801561284f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128739190615a6f565b10156128c15760405162461bcd60e51b815260206004820152600a60248201527f6e6f745f656e6f756768000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517f59e874ef000000000000000000000000000000000000000000000000000000008152336004820152602481018390526001604482015273ffffffffffffffffffffffffffffffffffffffff909116906359e874ef90606401600060405180830381600087803b15801561293a57600080fd5b505af115801561294e573d6000803e3d6000fd5b5050505061295b33614834565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146129c55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b60005b81811015611123576129e583838381811061243157612431615a88565b806129ef81615ae6565b9150506129c8565b60005473ffffffffffffffffffffffffffffffffffffffff163314612a5e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600d548110612aaf5760405162461bcd60e51b815260206004820152600d60248201527f6f6e6c795f6465637265617365000000000000000000000000000000000000006044820152606401610ebb565b612ab7612cd7565b601554612ac49190615b5c565b8111612b125760405162461bcd60e51b815260206004820152601060248201527f636162696e65745f7265736572766564000000000000000000000000000000006044820152606401610ebb565b600d55565b60005473ffffffffffffffffffffffffffffffffffffffff163314612b7e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b60195473ffffffffffffffffffffffffffffffffffffffff16612be35760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517f9149fe4000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526024820184905290911690639149fe4090604401600060405180830381600087803b158015612c5757600080fd5b505af1158015611f3d573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff163314612cd25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600e55565b6000612ce260075490565b905090565b606060028054610dd590615a1b565b60005473ffffffffffffffffffffffffffffffffffffffff163314612d5d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b601355565b60005473ffffffffffffffffffffffffffffffffffffffff163314612dc95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b6111236008838361535f565b73ffffffffffffffffffffffffffffffffffffffff8216331415612e3b5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610ebb565b33600081815260066020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612f395760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b828114612f885760405162461bcd60e51b815260206004820152600f60248201527f616d6f756e745f6d69736d6174636800000000000000000000000000000000006044820152606401610ebb565b6000805b82811015612fcc57838382818110612fa657612fa6615a88565b9050602002013582612fb89190615b5c565b915080612fc481615ae6565b915050612f8c565b50600d5460155482612fdc612cd7565b612fe69190615b5c565b612ff09190615b5c565b111561303e5760405162461bcd60e51b815260206004820152600860248201527f736f6c645f6f75740000000000000000000000000000000000000000000000006044820152606401610ebb565b506000805b84811015611f3d5760005b84848381811061306057613060615a88565b905060200201358110156130af5761309d87878481811061308357613083615a88565b905060200201602081019061309891906157c6565b614707565b806130a781615ae6565b91505061304e565b50806130ba81615ae6565b915050613043565b60005473ffffffffffffffffffffffffffffffffffffffff1633146131295760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b6111236009838361535f565b61313f338361439b565b6131b15760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610ebb565b6131bd848484846148c4565b50505050565b60008181526003602052604090205460609073ffffffffffffffffffffffffffffffffffffffff166132375760405162461bcd60e51b815260206004820152600860248201527f6e6f5f746f6b656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b604080518082018252600b81527f2e6a736f6e3f7661723d3100000000000000000000000000000000000000000060208083019190915282518082018452600080825286815260169092529290205490919060ff16156132c7575060408051808201909152600881527f26626f743d79657300000000000000000000000000000000000000000000000060208201525b604080516020808201835260008083528781526017909152919091205460ff1615613322575060408051808201909152600981527f26626f6f6b3d796573000000000000000000000000000000000000000000000060208201525b60006008805461333190615a1b565b90501161334d576040518060200160405280600081525061337f565b60086133588661494d565b84848460405160200161336f959493929190615c79565b6040516020818303038152906040525b95945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146133ef5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b805161340290600a906020840190615401565b507f38b9241ba197630c4329259c93d6a140b00cbe738808b738f460c5571d02b4426040516121a69060208082526005908201527f67726f7570000000000000000000000000000000000000000000000000000000604082015260600190565b60005473ffffffffffffffffffffffffffffffffffffffff1633146134c95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b601480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6008805461160390615a1b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146135845760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b6019805491151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179055565b600f54600090610100900460ff16156135e75750600090565b50600f5460ff1690565b600d5460155483613600612cd7565b61360a9190615b5c565b6136149190615b5c565b11156136625760405162461bcd60e51b815260206004820152600860248201527f736f6c645f6f75740000000000000000000000000000000000000000000000006044820152606401610ebb565b600b5433600090815260106020526040902054613680908490615b5c565b11156136ce5760405162461bcd60e51b815260206004820152600a60248201527f6d61785f6d696e746564000000000000000000000000000000000000000000006044820152606401610ebb565b600f54610100900460ff16156137265760405162461bcd60e51b815260206004820152600960248201527f69735f636c6f73656400000000000000000000000000000000000000000000006044820152606401610ebb565b61372f81614a7f565b61377b5760405162461bcd60e51b815260206004820152601160248201527f696e76616c69645f7369676e61747572650000000000000000000000000000006044820152606401610ebb565b3482600e5461378a9190615b1f565b146137d75760405162461bcd60e51b815260206004820152600f60248201527f696e636f72726563745f66756e647300000000000000000000000000000000006044820152606401610ebb565b33600090815260106020526040812080548492906137f6908490615b5c565b90915550600090505b828110156111235761381033614707565b8061381a81615ae6565b9150506137ff565b600d5460155482613831612cd7565b61383b9190615b5c565b6138459190615b5c565b11156138935760405162461bcd60e51b815260206004820152600860248201527f736f6c645f6f75740000000000000000000000000000000000000000000000006044820152606401610ebb565b600c548111156138e55760405162461bcd60e51b815260206004820152600c60248201527f6d61785f6d696e7461626c6500000000000000000000000000000000000000006044820152606401610ebb565b600f54610100900460ff161561393d5760405162461bcd60e51b815260206004820152600960248201527f69735f636c6f73656400000000000000000000000000000000000000000000006044820152606401610ebb565b600f5460ff1661398f5760405162461bcd60e51b815260206004820152600a60248201527f6e6f745f7075626c6963000000000000000000000000000000000000000000006044820152606401610ebb565b3481600e5461399e9190615b1f565b146139eb5760405162461bcd60e51b815260206004820152600f60248201527f696e636f72726563745f66756e647300000000000000000000000000000000006044820152606401610ebb565b60005b81811015613a11576139ff33614707565b80613a0981615ae6565b9150506139ee565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314613a7c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60145460009073ffffffffffffffffffffffffffffffffffffffff1615613bb4576014546040517fc455279100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015291821691841690829063c45527919060240160206040518083038186803b158015613b5457600080fd5b505afa158015613b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8c9190615cda565b73ffffffffffffffffffffffffffffffffffffffff161415613bb2576001915050610dc0565b505b73ffffffffffffffffffffffffffffffffffffffff80841660009081526006602090815260408083209386168352929052205460ff165b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314613c595760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b73ffffffffffffffffffffffffffffffffffffffff8116613ce25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ebb565b61295b816147bf565b60115460009073ffffffffffffffffffffffffffffffffffffffff16613d535760405162461bcd60e51b815260206004820152600e60248201527f6e6f5f7769746864726177616c730000000000000000000000000000000000006044820152606401610ebb565b60115473ffffffffffffffffffffffffffffffffffffffff163314613dba5760405162461bcd60e51b815260206004820152600b60248201527f6e6f745f616c6c6f7765640000000000000000000000000000000000000000006044820152606401610ebb565b47821115613e0a5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e745f66756e647300000000000000000000000000006044820152606401610ebb565b60405173ffffffffffffffffffffffffffffffffffffffff84169083156108fc029084906000818181858888f19350505050158015613e4d573d6000803e3d6000fd5b5060019392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314613ebe5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600d5481613eca612cd7565b613ed49190615b5c565b1115613f225760405162461bcd60e51b815260206004820152600860248201527f746f6f5f6d616e790000000000000000000000000000000000000000000000006044820152606401610ebb565b601555565b60005473ffffffffffffffffffffffffffffffffffffffff163314613f8e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b601980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331461403c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600f80548215157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161790556040517f38b9241ba197630c4329259c93d6a140b00cbe738808b738f460c5571d02b442906121a69060208082526008908201527f69735075626c6963000000000000000000000000000000000000000000000000604082015260600190565b5490565b80546001019055565b3b151590565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061417057507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610dc057507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610dc0565b600081815260056020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155819061421a8261244f565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000805b82811015613e4d573361428e85858481811061428257614282615a88565b9050602002013561244f565b73ffffffffffffffffffffffffffffffffffffffff16146142f15760405162461bcd60e51b815260206004820152600960248201527f6e6f745f6f776e657200000000000000000000000000000000000000000000006044820152606401610ebb565b806142fb81615ae6565b915050614264565b60008181526016602052604090205460ff16156143625760405162461bcd60e51b815260206004820152600f60248201527f616c72656164795f6861735f626f7400000000000000000000000000000000006044820152606401610ebb565b600090815260166020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60008181526003602052604081205473ffffffffffffffffffffffffffffffffffffffff166144325760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e00000000000000000000000000000000000000006064820152608401610ebb565b600061443d8361244f565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806144ac57508373ffffffffffffffffffffffffffffffffffffffff1661449484610f0f565b73ffffffffffffffffffffffffffffffffffffffff16145b806113e857506113e88185613ac3565b8273ffffffffffffffffffffffffffffffffffffffff166144dc8261244f565b73ffffffffffffffffffffffffffffffffffffffff16146145655760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201527f73206e6f74206f776e00000000000000000000000000000000000000000000006064820152608401610ebb565b73ffffffffffffffffffffffffffffffffffffffff82166145ed5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610ebb565b6145f86000826141c0565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260046020526040812080546001929061462e908490615b74565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152600460205260408120805460019290614669908490615b5c565b909155505060008181526003602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6000613beb8284615b1f565b6000613beb8284615d26565b6147198161471460075490565b614b6a565b61295b600780546001019055565b60008181526017602052604090205460ff16156147865760405162461bcd60e51b815260206004820152600f60248201527f616c72656164795f6861735f626f7400000000000000000000000000000000006044820152606401610ebb565b600090815260176020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600a60185460016148459190615b5c565b106148925760405162461bcd60e51b815260206004820152600e60248201527f6e6f6e655f617661696c61626c650000000000000000000000000000000000006044820152606401610ebb565b601880549060019060006148a68385615b5c565b92505081905550613a11308383604051806020016040528060008152505b6148cf8484846144bc565b6148db84848484614b84565b6131bd5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610ebb565b60608161498d57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156149b757806149a181615ae6565b91506149b09050600a83615d26565b9150614991565b60008167ffffffffffffffff8111156149d2576149d2615677565b6040519080825280601f01601f1916602001820160405280156149fc576020820181803683370190505b5090505b84156113e857614a11600183615b74565b9150614a1e600a86615d3a565b614a29906030615b5c565b60f81b818381518110614a3e57614a3e615a88565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350614a78600a86615d26565b9450614a00565b6000806009600a33604051602001614a9993929190615d4e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060125490915073ffffffffffffffffffffffffffffffffffffffff16614b4c84614b46846040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b90614d66565b73ffffffffffffffffffffffffffffffffffffffff16149392505050565b613a11828260405180602001604052806000815250614d8a565b600073ffffffffffffffffffffffffffffffffffffffff84163b15614d5e576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290614bfb903390899088908890600401615d98565b602060405180830381600087803b158015614c1557600080fd5b505af1925050508015614c63575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252614c6091810190615de1565b60015b614d13573d808015614c91576040519150601f19603f3d011682016040523d82523d6000602084013e614c96565b606091505b508051614d0b5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610ebb565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a02000000000000000000000000000000000000000000000000000000001490506113e8565b5060016113e8565b6000806000614d758585614e13565b91509150614d8281614e80565b509392505050565b614d948383615071565b614da16000848484614b84565b6111235760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610ebb565b600080825160411415614e4a5760208301516040840151606085015160001a614e3e878285856151ff565b94509450505050611713565b825160401415614e745760208301516040840151614e69868383615317565b935093505050611713565b50600090506002611713565b6000816004811115614e9457614e94615dfe565b1415614e9d5750565b6001816004811115614eb157614eb1615dfe565b1415614eff5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610ebb565b6002816004811115614f1357614f13615dfe565b1415614f615760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610ebb565b6003816004811115614f7557614f75615dfe565b1415614fe95760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610ebb565b6004816004811115614ffd57614ffd615dfe565b141561295b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610ebb565b73ffffffffffffffffffffffffffffffffffffffff82166150d45760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610ebb565b60008181526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16156151465760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610ebb565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020526040812080546001929061517c908490615b5c565b909155505060008181526003602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115615236575060009050600361530e565b8460ff16601b1415801561524e57508460ff16601c14155b1561525f575060009050600461530e565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156152b3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166153075760006001925092505061530e565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b01615351878288856151ff565b935093505050935093915050565b82805461536b90615a1b565b90600052602060002090601f01602090048101928261538d57600085556153f1565b82601f106153c4578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556153f1565b828001600101855582156153f1579182015b828111156153f15782358255916020019190600101906153d6565b506153fd929150615475565b5090565b82805461540d90615a1b565b90600052602060002090601f01602090048101928261542f57600085556153f1565b82601f1061544857805160ff19168380011785556153f1565b828001600101855582156153f1579182015b828111156153f157825182559160200191906001019061545a565b5b808211156153fd5760008155600101615476565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461295b57600080fd5b6000602082840312156154ca57600080fd5b8135613beb8161548a565b60005b838110156154f05781810151838201526020016154d8565b838111156131bd5750506000910152565b600081518084526155198160208601602086016154d5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000613beb6020830184615501565b801515811461295b57600080fd5b60006020828403121561557e57600080fd5b8135613beb8161555e565b60006020828403121561559b57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461295b57600080fd5b600080604083850312156155d757600080fd5b82356155e2816155a2565b946020939093013593505050565b60008083601f84011261560257600080fd5b50813567ffffffffffffffff81111561561a57600080fd5b6020830191508360208260051b850101111561171357600080fd5b6000806020838503121561564857600080fd5b823567ffffffffffffffff81111561565f57600080fd5b61566b858286016155f0565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600067ffffffffffffffff808411156156c1576156c1615677565b604051601f85017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561570757615707615677565b8160405280935085815286868601111561572057600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261574b57600080fd5b613beb838335602085016156a6565b6000806000806080858703121561577057600080fd5b843561577b816155a2565b9350602085013561578b816155a2565b925060408501359150606085013567ffffffffffffffff8111156157ae57600080fd5b6157ba8782880161573a565b91505092959194509250565b6000602082840312156157d857600080fd5b8135613beb816155a2565b6000806000606084860312156157f857600080fd5b8335615803816155a2565b92506020840135615813816155a2565b929592945050506040919091013590565b6000806040838503121561583757600080fd5b50508035926020909101359150565b6000806000806040858703121561585c57600080fd5b843567ffffffffffffffff8082111561587457600080fd5b615880888389016155f0565b9096509450602087013591508082111561589957600080fd5b506158a6878288016155f0565b95989497509550505050565b600080602083850312156158c557600080fd5b823567ffffffffffffffff808211156158dd57600080fd5b818501915085601f8301126158f157600080fd5b81358181111561590057600080fd5b86602082850101111561591257600080fd5b60209290920196919550909350505050565b6000806040838503121561593757600080fd5b8235615942816155a2565b915060208301356159528161555e565b809150509250929050565b60006020828403121561596f57600080fd5b813567ffffffffffffffff81111561598657600080fd5b8201601f8101841361599757600080fd5b6113e8848235602084016156a6565b600080604083850312156159b957600080fd5b82359150602083013567ffffffffffffffff8111156159d757600080fd5b6159e38582860161573a565b9150509250929050565b60008060408385031215615a0057600080fd5b8235615a0b816155a2565b91506020830135615952816155a2565b600181811c90821680615a2f57607f821691505b60208210811415615a69577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600060208284031215615a8157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615b1857615b18615ab7565b5060010190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615b5757615b57615ab7565b500290565b60008219821115615b6f57615b6f615ab7565b500190565b600082821015615b8657615b86615ab7565b500390565b600060208284031215615b9d57600080fd5b8151613beb8161555e565b8054600090600181811c9080831680615bc257607f831692505b6020808410821415615bfd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b818015615c115760018114615c4057615c6d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861689528489019650615c6d565b60008881526020902060005b86811015615c655781548b820152908501908301615c4c565b505084890196505b50505050505092915050565b6000615c858288615ba8565b8651615c95818360208b016154d5565b8651910190615ca8818360208a016154d5565b8551910190615cbb8183602089016154d5565b8451910190615cce8183602088016154d5565b01979650505050505050565b600060208284031215615cec57600080fd5b8151613beb816155a2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615d3557615d35615cf7565b500490565b600082615d4957615d49615cf7565b500690565b6000615d63615d5d8387615ba8565b85615ba8565b60609390931b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000168352505060140192915050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152615dd76080830184615501565b9695505050505050565b600060208284031215615df357600080fd5b8151613beb8161548a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220aced6b5fac40f572f2cbeefbbfa8e32bedbe94eb87324054954035292f3691c364736f6c634300080900334552433732313a207472616e7366657220746f206e6f6e20455243373231526568747470733a2f2f73746f726167652e686173686b752e636f6d2f6170692f736f74682f6d61696e2f

Deployed Bytecode

0x60806040526004361061044a5760003560e01c80638edb25a011610243578063d26ea6c011610143578063e8c61831116100bb578063f3fef3a31161008a578063f75451f81161006f578063f75451f814610cfa578063fdab3b3f14610d1a578063fee99fb614610d3a57600080fd5b8063f3fef3a314610cba578063f71b40ff14610cda57600080fd5b8063e8c6183114610c20578063e985e9c514610c4d578063f2bcd02214610c6d578063f2fde38b14610c9a57600080fd5b8063d870155411610112578063dc9a1535116100f7578063dc9a153514610bd0578063e0d11a4714610bea578063e831574214610c0a57600080fd5b8063d870155414610baa578063da69c08314610bbd57600080fd5b8063d26ea6c014610b40578063d547cfb714610b60578063d6a2a4bc14610b75578063d832d92f14610b9557600080fd5b8063a0bcfc7f116101d6578063b88d4fde116101a5578063c87b56dd1161018a578063c87b56dd14610ad3578063c97b973014610af3578063cd7c032614610b1357600080fd5b8063b88d4fde14610a94578063c2b6b58c14610ab457600080fd5b8063a0bcfc7f14610a14578063a22cb46514610a34578063a645ff5f14610a54578063af42d10614610a7457600080fd5b806395d89b411161021257806395d89b41146109b35780639a4fc640146109c85780639f67756d146109e8578063a035b1fe146109fe57600080fd5b80638edb25a01461093e5780639149fe401461095e57806391b7f5ed1461097e5780639499ac541461099e57600080fd5b80633943380c1161034e5780635cffabb1116102e1578063715018a6116102b0578063800b434411610295578063800b4344146108c1578063835b57b9146108f35780638da5cb5b1461091357600080fd5b8063715018a61461088c5780637c39e0e0146108a157600080fd5b80635cffabb1146108095780636352211e1461081f5780636d08557a1461083f57806370a082311461086c57600080fd5b806349668b4a1161031d57806349668b4a146107865780635444d103146107a657806354610481146107c6578063572849c4146107f357600080fd5b80633943380c1461070957806342842e0e1461071e578063429a1bb01461073e578063434735ff1461075357600080fd5b80631b2a1e32116103e157806323b872dd116103b05780632a55205a116103955780632a55205a1461067d5780632ca51e22146106c95780632e6cebe5146106e957600080fd5b806323b872dd1461064857806329e7ef2d1461066857600080fd5b80631b2a1e32146105c25780631e14d44b146105d85780631f9ba96b146105f857806321b8092e1461062857600080fd5b8063081812fc1161041d578063081812fc146104ec578063095ea7b3146105315780630f2abec014610551578063150b7a021461057157600080fd5b806301f569971461044f57806301ffc9a71461047857806306fdde03146104a857806307953da1146104ca575b600080fd5b34801561045b57600080fd5b50610465600c5481565b6040519081526020015b60405180910390f35b34801561048457600080fd5b506104986104933660046154b8565b610d6a565b604051901515815260200161046f565b3480156104b457600080fd5b506104bd610dc6565b60405161046f919061554b565b3480156104d657600080fd5b506104ea6104e536600461556c565b610e58565b005b3480156104f857600080fd5b5061050c610507366004615589565b610f0f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161046f565b34801561053d57600080fd5b506104ea61054c3660046155c4565b610fcf565b34801561055d57600080fd5b506104ea61056c366004615635565b611128565b34801561057d57600080fd5b5061059161058c36600461575a565b6113c6565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161046f565b3480156105ce57600080fd5b5061046560185481565b3480156105e457600080fd5b506104ea6105f3366004615589565b6113f0565b34801561060457600080fd5b50610498610613366004615589565b60176020526000908152604090205460ff1681565b34801561063457600080fd5b506104ea6106433660046157c6565b61145c565b34801561065457600080fd5b506104ea6106633660046157e3565b61156f565b34801561067457600080fd5b506104bd6115f6565b34801561068957600080fd5b5061069d610698366004615824565b611684565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161046f565b3480156106d557600080fd5b506104ea6106e4366004615846565b61171a565b3480156106f557600080fd5b506104ea610704366004615589565b611f45565b34801561071557600080fd5b506104bd611fb1565b34801561072a57600080fd5b506104ea6107393660046157e3565b611fbe565b34801561074a57600080fd5b50610465611fd9565b34801561075f57600080fd5b50601954610498907501000000000000000000000000000000000000000000900460ff1681565b34801561079257600080fd5b506104ea6107a136600461556c565b6120ad565b3480156107b257600080fd5b506104ea6107c1366004615635565b6121b1565b3480156107d257600080fd5b506104656107e13660046157c6565b60106020526000908152604090205481565b3480156107ff57600080fd5b50610465600b5481565b34801561081557600080fd5b5061046560155481565b34801561082b57600080fd5b5061050c61083a366004615589565b61244f565b34801561084b57600080fd5b5060195461050c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561087857600080fd5b506104656108873660046157c6565b6124e7565b34801561089857600080fd5b506104ea61259b565b3480156108ad57600080fd5b506104ea6108bc366004615589565b61260e565b3480156108cd57600080fd5b506019546104989074010000000000000000000000000000000000000000900460ff1681565b3480156108ff57600080fd5b506104ea61090e366004615635565b61295e565b34801561091f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661050c565b34801561094a57600080fd5b506104ea610959366004615589565b6129f7565b34801561096a57600080fd5b506104ea6109793660046155c4565b612b17565b34801561098a57600080fd5b506104ea610999366004615589565b612c6b565b3480156109aa57600080fd5b50610465612cd7565b3480156109bf57600080fd5b506104bd612ce7565b3480156109d457600080fd5b506104ea6109e3366004615589565b612cf6565b3480156109f457600080fd5b5061046560135481565b348015610a0a57600080fd5b50610465600e5481565b348015610a2057600080fd5b506104ea610a2f3660046158b2565b612d62565b348015610a4057600080fd5b506104ea610a4f366004615924565b612dd5565b348015610a6057600080fd5b506104ea610a6f366004615846565b612ed2565b348015610a8057600080fd5b506104ea610a8f3660046158b2565b6130c2565b348015610aa057600080fd5b506104ea610aaf36600461575a565b613135565b348015610ac057600080fd5b50600f5461049890610100900460ff1681565b348015610adf57600080fd5b506104bd610aee366004615589565b6131c3565b348015610aff57600080fd5b506104ea610b0e36600461595d565b613388565b348015610b1f57600080fd5b5060145461050c9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b4c57600080fd5b506104ea610b5b3660046157c6565b613462565b348015610b6c57600080fd5b506104bd613510565b348015610b8157600080fd5b506104ea610b9036600461556c565b61351d565b348015610ba157600080fd5b506104986135ce565b6104ea610bb83660046159a6565b6135f1565b6104ea610bcb366004615589565b613822565b348015610bdc57600080fd5b50600f546104989060ff1681565b348015610bf657600080fd5b506104ea610c053660046157c6565b613a15565b348015610c1657600080fd5b50610465600d5481565b348015610c2c57600080fd5b5060125461050c9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610c5957600080fd5b50610498610c683660046159ed565b613ac3565b348015610c7957600080fd5b5060115461050c9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610ca657600080fd5b506104ea610cb53660046157c6565b613bf2565b348015610cc657600080fd5b50610498610cd53660046155c4565b613ceb565b348015610ce657600080fd5b506104ea610cf5366004615589565b613e57565b348015610d0657600080fd5b506104ea610d153660046157c6565b613f27565b348015610d2657600080fd5b506104ea610d3536600461556c565b613fd5565b348015610d4657600080fd5b50610498610d55366004615589565b60166020526000908152604090205460ff1681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a000000000000000000000000000000000000000000000000000000001480610dc05750610dc0826140dd565b92915050565b606060018054610dd590615a1b565b80601f0160208091040260200160405190810160405280929190818152602001828054610e0190615a1b565b8015610e4e5780601f10610e2357610100808354040283529160200191610e4e565b820191906000526020600020905b815481529060010190602001808311610e3157829003601f168201915b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ec45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b601980549115157501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60008181526003602052604081205473ffffffffffffffffffffffffffffffffffffffff16610fa65760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e00000000000000000000000000000000000000006064820152608401610ebb565b5060009081526005602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6000610fda8261244f565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561107e5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610ebb565b3373ffffffffffffffffffffffffffffffffffffffff821614806110a757506110a78133613ac3565b6111195760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610ebb565b61112383836141c0565b505050565b60195473ffffffffffffffffffffffffffffffffffffffff1661118d5760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b6019547501000000000000000000000000000000000000000000900460ff166111f85760405162461bcd60e51b815260206004820152600860248201527f6e6f745f6f70656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517efdd58e00000000000000000000000000000000000000000000000000000000815233600482015260066024820152829173ffffffffffffffffffffffffffffffffffffffff169062fdd58e9060440160206040518083038186803b15801561126657600080fd5b505afa15801561127a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129e9190615a6f565b10156112ec5760405162461bcd60e51b815260206004820152600760248201527f6e6f5f6974656d000000000000000000000000000000000000000000000000006044820152606401610ebb565b6112f68282614260565b506019546040517f59e874ef000000000000000000000000000000000000000000000000000000008152336004820152600660248201526044810183905273ffffffffffffffffffffffffffffffffffffffff909116906359e874ef90606401600060405180830381600087803b15801561137057600080fd5b505af1158015611384573d6000803e3d6000fd5b5050505060005b81811015611123576113b48383838181106113a8576113a8615a88565b90506020020135614303565b806113be81615ae6565b91505061138b565b7f150b7a02000000000000000000000000000000000000000000000000000000005b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146114575760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600b55565b60115473ffffffffffffffffffffffffffffffffffffffff166114c15760405162461bcd60e51b815260206004820152600e60248201527f6e6f5f7769746864726177616c730000000000000000000000000000000000006044820152606401610ebb565b60115473ffffffffffffffffffffffffffffffffffffffff1633146115285760405162461bcd60e51b815260206004820152600b60248201527f6e6f745f616c6c6f7765640000000000000000000000000000000000000000006044820152606401610ebb565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611579338261439b565b6115eb5760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610ebb565b6111238383836144bc565b600a805461160390615a1b565b80601f016020809104026020016040519081016040528092919081815260200182805461162f90615a1b565b801561167c5780601f106116515761010080835404028352916020019161167c565b820191906000526020600020905b81548152906001019060200180831161165f57829003601f168201915b505050505081565b600082815260036020526040812054819073ffffffffffffffffffffffffffffffffffffffff166116f75760405162461bcd60e51b815260206004820152600860248201527f6e6f5f746f6b656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b3061170e611707856013546146ef565b60646146fb565b915091505b9250929050565b60195473ffffffffffffffffffffffffffffffffffffffff1661177f5760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b60195474010000000000000000000000000000000000000000900460ff166117e95760405162461bcd60e51b815260206004820152600860248201527f6e6f745f6f70656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b826118365760405162461bcd60e51b815260206004820152600860248201527f6e6f5f6974656d730000000000000000000000000000000000000000000000006044820152606401610ebb565b8281146118855760405162461bcd60e51b815260206004820152600f60248201527f6c656e6774685f6d69736d6174636800000000000000000000000000000000006044820152606401610ebb565b600683106118d55760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69645f6974656d73000000000000000000000000000000000000006044820152606401610ebb565b60005b83811015611b095760008383838181106118f4576118f4615a88565b90506020020135116119485760405162461bcd60e51b815260206004820152600d60248201527f7175616e746974795f7a65726f000000000000000000000000000000000000006044820152606401610ebb565b82828281811061195a5761195a615a88565b601954602090910292909201359173ffffffffffffffffffffffffffffffffffffffff16905062fdd58e3388888681811061199757611997615a88565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815273ffffffffffffffffffffffffffffffffffffffff9094166004850152602002919091013560248301525060440160206040518083038186803b158015611a0957600080fd5b505afa158015611a1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a419190615a6f565b1015611a8f5760405162461bcd60e51b815260206004820152600760248201527f6e6f5f6974656d000000000000000000000000000000000000000000000000006044820152606401610ebb565b6005858583818110611aa357611aa3615a88565b9050602002013510611af75760405162461bcd60e51b815260206004820152600c60248201527f696e76616c69645f6974656d00000000000000000000000000000000000000006044820152606401610ebb565b80611b0181615ae6565b9150506118d8565b506000805b84811015611efe5760195473ffffffffffffffffffffffffffffffffffffffff166359e874ef33888885818110611b4757611b47615a88565b90506020020135878786818110611b6057611b60615a88565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff9095166004860152602485019390935250602090910201356044820152606401600060405180830381600087803b158015611bdb57600080fd5b505af1158015611bef573d6000803e3d6000fd5b50505050838382818110611c0557611c05615a88565b601954602090910292909201359173ffffffffffffffffffffffffffffffffffffffff169050639d354516888885818110611c4257611c42615a88565b905060200201356040518263ffffffff1660e01b8152600401611c6791815260200190565b60206040518083038186803b158015611c7f57600080fd5b505afa158015611c93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb79190615a6f565b611cc19190615b1f565b611ccb9083615b5c565b9150858582818110611cdf57611cdf615a88565b9050602002013560021415611db95760195473ffffffffffffffffffffffffffffffffffffffff1663e7228e61336005878786818110611d2157611d21615a88565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff9095166004860152602485019390935250602090910201356044820152606401600060405180830381600087803b158015611d9c57600080fd5b505af1158015611db0573d6000803e3d6000fd5b50505050611eec565b858582818110611dcb57611dcb615a88565b9050602002013560031415611e0d5760195473ffffffffffffffffffffffffffffffffffffffff1663e7228e61336006878786818110611d2157611d21615a88565b858582818110611e1f57611e1f615a88565b9050602002013560041415611eec5760195473ffffffffffffffffffffffffffffffffffffffff16639149fe4033868685818110611e5f57611e5f615a88565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815273ffffffffffffffffffffffffffffffffffffffff90941660048501526020029190910135602483015250604401600060405180830381600087803b158015611ed357600080fd5b505af1158015611ee7573d6000803e3d6000fd5b505050505b80611ef681615ae6565b915050611b0e565b508060156000828254611f119190615b74565b90915550600090505b81811015611f3d57611f2b33614707565b80611f3581615ae6565b915050611f1a565b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611fac5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600c55565b6009805461160390615a1b565b61112383838360405180602001604052806000815250613135565b60115460009073ffffffffffffffffffffffffffffffffffffffff166120415760405162461bcd60e51b815260206004820152600e60248201527f6e6f5f7769746864726177616c730000000000000000000000000000000000006044820152606401610ebb565b60115473ffffffffffffffffffffffffffffffffffffffff1633146120a85760405162461bcd60e51b815260206004820152600b60248201527f6e6f745f616c6c6f7765640000000000000000000000000000000000000000006044820152606401610ebb565b504790565b60005473ffffffffffffffffffffffffffffffffffffffff1633146121145760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600f8054821515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9091161790556040517f38b9241ba197630c4329259c93d6a140b00cbe738808b738f460c5571d02b442906121a69060208082526008908201527f6973436c6f736564000000000000000000000000000000000000000000000000604082015260600190565b60405180910390a150565b60195473ffffffffffffffffffffffffffffffffffffffff166122165760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b6019547501000000000000000000000000000000000000000000900460ff166122815760405162461bcd60e51b815260206004820152600860248201527f6e6f745f6f70656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517efdd58e00000000000000000000000000000000000000000000000000000000815233600482015260056024820152829173ffffffffffffffffffffffffffffffffffffffff169062fdd58e9060440160206040518083038186803b1580156122ef57600080fd5b505afa158015612303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123279190615a6f565b10156123755760405162461bcd60e51b815260206004820152600760248201527f6e6f5f6974656d000000000000000000000000000000000000000000000000006044820152606401610ebb565b61237f8282614260565b506019546040517f59e874ef000000000000000000000000000000000000000000000000000000008152336004820152600560248201526044810183905273ffffffffffffffffffffffffffffffffffffffff909116906359e874ef90606401600060405180830381600087803b1580156123f957600080fd5b505af115801561240d573d6000803e3d6000fd5b5050505060005b818110156111235761243d83838381811061243157612431615a88565b90506020020135614727565b8061244781615ae6565b915050612414565b60008181526003602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610dc05760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201527f656e7420746f6b656e00000000000000000000000000000000000000000000006064820152608401610ebb565b600073ffffffffffffffffffffffffffffffffffffffff82166125725760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610ebb565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205490565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126025760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b61260c60006147bf565b565b60195473ffffffffffffffffffffffffffffffffffffffff166126735760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b6019547501000000000000000000000000000000000000000000900460ff166126de5760405162461bcd60e51b815260206004820152600860248201527f6e6f745f6f70656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517f4496a4530000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff90911690634496a4539060240160206040518083038186803b15801561274857600080fd5b505afa15801561275c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127809190615b8b565b6127cc5760405162461bcd60e51b815260206004820152600a60248201527f6e6f745f77696e6e6572000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517efdd58e0000000000000000000000000000000000000000000000000000000081523360048201526024810183905260019173ffffffffffffffffffffffffffffffffffffffff169062fdd58e9060440160206040518083038186803b15801561283b57600080fd5b505afa15801561284f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128739190615a6f565b10156128c15760405162461bcd60e51b815260206004820152600a60248201527f6e6f745f656e6f756768000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517f59e874ef000000000000000000000000000000000000000000000000000000008152336004820152602481018390526001604482015273ffffffffffffffffffffffffffffffffffffffff909116906359e874ef90606401600060405180830381600087803b15801561293a57600080fd5b505af115801561294e573d6000803e3d6000fd5b5050505061295b33614834565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146129c55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b60005b81811015611123576129e583838381811061243157612431615a88565b806129ef81615ae6565b9150506129c8565b60005473ffffffffffffffffffffffffffffffffffffffff163314612a5e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600d548110612aaf5760405162461bcd60e51b815260206004820152600d60248201527f6f6e6c795f6465637265617365000000000000000000000000000000000000006044820152606401610ebb565b612ab7612cd7565b601554612ac49190615b5c565b8111612b125760405162461bcd60e51b815260206004820152601060248201527f636162696e65745f7265736572766564000000000000000000000000000000006044820152606401610ebb565b600d55565b60005473ffffffffffffffffffffffffffffffffffffffff163314612b7e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b60195473ffffffffffffffffffffffffffffffffffffffff16612be35760405162461bcd60e51b815260206004820152600a60248201527f6e6f5f636162696e6574000000000000000000000000000000000000000000006044820152606401610ebb565b6019546040517f9149fe4000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526024820184905290911690639149fe4090604401600060405180830381600087803b158015612c5757600080fd5b505af1158015611f3d573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff163314612cd25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600e55565b6000612ce260075490565b905090565b606060028054610dd590615a1b565b60005473ffffffffffffffffffffffffffffffffffffffff163314612d5d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b601355565b60005473ffffffffffffffffffffffffffffffffffffffff163314612dc95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b6111236008838361535f565b73ffffffffffffffffffffffffffffffffffffffff8216331415612e3b5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610ebb565b33600081815260066020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612f395760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b828114612f885760405162461bcd60e51b815260206004820152600f60248201527f616d6f756e745f6d69736d6174636800000000000000000000000000000000006044820152606401610ebb565b6000805b82811015612fcc57838382818110612fa657612fa6615a88565b9050602002013582612fb89190615b5c565b915080612fc481615ae6565b915050612f8c565b50600d5460155482612fdc612cd7565b612fe69190615b5c565b612ff09190615b5c565b111561303e5760405162461bcd60e51b815260206004820152600860248201527f736f6c645f6f75740000000000000000000000000000000000000000000000006044820152606401610ebb565b506000805b84811015611f3d5760005b84848381811061306057613060615a88565b905060200201358110156130af5761309d87878481811061308357613083615a88565b905060200201602081019061309891906157c6565b614707565b806130a781615ae6565b91505061304e565b50806130ba81615ae6565b915050613043565b60005473ffffffffffffffffffffffffffffffffffffffff1633146131295760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b6111236009838361535f565b61313f338361439b565b6131b15760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610ebb565b6131bd848484846148c4565b50505050565b60008181526003602052604090205460609073ffffffffffffffffffffffffffffffffffffffff166132375760405162461bcd60e51b815260206004820152600860248201527f6e6f5f746f6b656e0000000000000000000000000000000000000000000000006044820152606401610ebb565b604080518082018252600b81527f2e6a736f6e3f7661723d3100000000000000000000000000000000000000000060208083019190915282518082018452600080825286815260169092529290205490919060ff16156132c7575060408051808201909152600881527f26626f743d79657300000000000000000000000000000000000000000000000060208201525b604080516020808201835260008083528781526017909152919091205460ff1615613322575060408051808201909152600981527f26626f6f6b3d796573000000000000000000000000000000000000000000000060208201525b60006008805461333190615a1b565b90501161334d576040518060200160405280600081525061337f565b60086133588661494d565b84848460405160200161336f959493929190615c79565b6040516020818303038152906040525b95945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146133ef5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b805161340290600a906020840190615401565b507f38b9241ba197630c4329259c93d6a140b00cbe738808b738f460c5571d02b4426040516121a69060208082526005908201527f67726f7570000000000000000000000000000000000000000000000000000000604082015260600190565b60005473ffffffffffffffffffffffffffffffffffffffff1633146134c95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b601480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6008805461160390615a1b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146135845760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b6019805491151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179055565b600f54600090610100900460ff16156135e75750600090565b50600f5460ff1690565b600d5460155483613600612cd7565b61360a9190615b5c565b6136149190615b5c565b11156136625760405162461bcd60e51b815260206004820152600860248201527f736f6c645f6f75740000000000000000000000000000000000000000000000006044820152606401610ebb565b600b5433600090815260106020526040902054613680908490615b5c565b11156136ce5760405162461bcd60e51b815260206004820152600a60248201527f6d61785f6d696e746564000000000000000000000000000000000000000000006044820152606401610ebb565b600f54610100900460ff16156137265760405162461bcd60e51b815260206004820152600960248201527f69735f636c6f73656400000000000000000000000000000000000000000000006044820152606401610ebb565b61372f81614a7f565b61377b5760405162461bcd60e51b815260206004820152601160248201527f696e76616c69645f7369676e61747572650000000000000000000000000000006044820152606401610ebb565b3482600e5461378a9190615b1f565b146137d75760405162461bcd60e51b815260206004820152600f60248201527f696e636f72726563745f66756e647300000000000000000000000000000000006044820152606401610ebb565b33600090815260106020526040812080548492906137f6908490615b5c565b90915550600090505b828110156111235761381033614707565b8061381a81615ae6565b9150506137ff565b600d5460155482613831612cd7565b61383b9190615b5c565b6138459190615b5c565b11156138935760405162461bcd60e51b815260206004820152600860248201527f736f6c645f6f75740000000000000000000000000000000000000000000000006044820152606401610ebb565b600c548111156138e55760405162461bcd60e51b815260206004820152600c60248201527f6d61785f6d696e7461626c6500000000000000000000000000000000000000006044820152606401610ebb565b600f54610100900460ff161561393d5760405162461bcd60e51b815260206004820152600960248201527f69735f636c6f73656400000000000000000000000000000000000000000000006044820152606401610ebb565b600f5460ff1661398f5760405162461bcd60e51b815260206004820152600a60248201527f6e6f745f7075626c6963000000000000000000000000000000000000000000006044820152606401610ebb565b3481600e5461399e9190615b1f565b146139eb5760405162461bcd60e51b815260206004820152600f60248201527f696e636f72726563745f66756e647300000000000000000000000000000000006044820152606401610ebb565b60005b81811015613a11576139ff33614707565b80613a0981615ae6565b9150506139ee565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314613a7c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60145460009073ffffffffffffffffffffffffffffffffffffffff1615613bb4576014546040517fc455279100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015291821691841690829063c45527919060240160206040518083038186803b158015613b5457600080fd5b505afa158015613b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8c9190615cda565b73ffffffffffffffffffffffffffffffffffffffff161415613bb2576001915050610dc0565b505b73ffffffffffffffffffffffffffffffffffffffff80841660009081526006602090815260408083209386168352929052205460ff165b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314613c595760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b73ffffffffffffffffffffffffffffffffffffffff8116613ce25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ebb565b61295b816147bf565b60115460009073ffffffffffffffffffffffffffffffffffffffff16613d535760405162461bcd60e51b815260206004820152600e60248201527f6e6f5f7769746864726177616c730000000000000000000000000000000000006044820152606401610ebb565b60115473ffffffffffffffffffffffffffffffffffffffff163314613dba5760405162461bcd60e51b815260206004820152600b60248201527f6e6f745f616c6c6f7765640000000000000000000000000000000000000000006044820152606401610ebb565b47821115613e0a5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e745f66756e647300000000000000000000000000006044820152606401610ebb565b60405173ffffffffffffffffffffffffffffffffffffffff84169083156108fc029084906000818181858888f19350505050158015613e4d573d6000803e3d6000fd5b5060019392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314613ebe5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600d5481613eca612cd7565b613ed49190615b5c565b1115613f225760405162461bcd60e51b815260206004820152600860248201527f746f6f5f6d616e790000000000000000000000000000000000000000000000006044820152606401610ebb565b601555565b60005473ffffffffffffffffffffffffffffffffffffffff163314613f8e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b601980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331461403c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ebb565b600f80548215157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161790556040517f38b9241ba197630c4329259c93d6a140b00cbe738808b738f460c5571d02b442906121a69060208082526008908201527f69735075626c6963000000000000000000000000000000000000000000000000604082015260600190565b5490565b80546001019055565b3b151590565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061417057507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610dc057507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610dc0565b600081815260056020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155819061421a8261244f565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000805b82811015613e4d573361428e85858481811061428257614282615a88565b9050602002013561244f565b73ffffffffffffffffffffffffffffffffffffffff16146142f15760405162461bcd60e51b815260206004820152600960248201527f6e6f745f6f776e657200000000000000000000000000000000000000000000006044820152606401610ebb565b806142fb81615ae6565b915050614264565b60008181526016602052604090205460ff16156143625760405162461bcd60e51b815260206004820152600f60248201527f616c72656164795f6861735f626f7400000000000000000000000000000000006044820152606401610ebb565b600090815260166020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60008181526003602052604081205473ffffffffffffffffffffffffffffffffffffffff166144325760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e00000000000000000000000000000000000000006064820152608401610ebb565b600061443d8361244f565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806144ac57508373ffffffffffffffffffffffffffffffffffffffff1661449484610f0f565b73ffffffffffffffffffffffffffffffffffffffff16145b806113e857506113e88185613ac3565b8273ffffffffffffffffffffffffffffffffffffffff166144dc8261244f565b73ffffffffffffffffffffffffffffffffffffffff16146145655760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201527f73206e6f74206f776e00000000000000000000000000000000000000000000006064820152608401610ebb565b73ffffffffffffffffffffffffffffffffffffffff82166145ed5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610ebb565b6145f86000826141c0565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260046020526040812080546001929061462e908490615b74565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152600460205260408120805460019290614669908490615b5c565b909155505060008181526003602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6000613beb8284615b1f565b6000613beb8284615d26565b6147198161471460075490565b614b6a565b61295b600780546001019055565b60008181526017602052604090205460ff16156147865760405162461bcd60e51b815260206004820152600f60248201527f616c72656164795f6861735f626f7400000000000000000000000000000000006044820152606401610ebb565b600090815260176020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600a60185460016148459190615b5c565b106148925760405162461bcd60e51b815260206004820152600e60248201527f6e6f6e655f617661696c61626c650000000000000000000000000000000000006044820152606401610ebb565b601880549060019060006148a68385615b5c565b92505081905550613a11308383604051806020016040528060008152505b6148cf8484846144bc565b6148db84848484614b84565b6131bd5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610ebb565b60608161498d57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156149b757806149a181615ae6565b91506149b09050600a83615d26565b9150614991565b60008167ffffffffffffffff8111156149d2576149d2615677565b6040519080825280601f01601f1916602001820160405280156149fc576020820181803683370190505b5090505b84156113e857614a11600183615b74565b9150614a1e600a86615d3a565b614a29906030615b5c565b60f81b818381518110614a3e57614a3e615a88565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350614a78600a86615d26565b9450614a00565b6000806009600a33604051602001614a9993929190615d4e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060125490915073ffffffffffffffffffffffffffffffffffffffff16614b4c84614b46846040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b90614d66565b73ffffffffffffffffffffffffffffffffffffffff16149392505050565b613a11828260405180602001604052806000815250614d8a565b600073ffffffffffffffffffffffffffffffffffffffff84163b15614d5e576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290614bfb903390899088908890600401615d98565b602060405180830381600087803b158015614c1557600080fd5b505af1925050508015614c63575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252614c6091810190615de1565b60015b614d13573d808015614c91576040519150601f19603f3d011682016040523d82523d6000602084013e614c96565b606091505b508051614d0b5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610ebb565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a02000000000000000000000000000000000000000000000000000000001490506113e8565b5060016113e8565b6000806000614d758585614e13565b91509150614d8281614e80565b509392505050565b614d948383615071565b614da16000848484614b84565b6111235760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610ebb565b600080825160411415614e4a5760208301516040840151606085015160001a614e3e878285856151ff565b94509450505050611713565b825160401415614e745760208301516040840151614e69868383615317565b935093505050611713565b50600090506002611713565b6000816004811115614e9457614e94615dfe565b1415614e9d5750565b6001816004811115614eb157614eb1615dfe565b1415614eff5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610ebb565b6002816004811115614f1357614f13615dfe565b1415614f615760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610ebb565b6003816004811115614f7557614f75615dfe565b1415614fe95760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610ebb565b6004816004811115614ffd57614ffd615dfe565b141561295b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610ebb565b73ffffffffffffffffffffffffffffffffffffffff82166150d45760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610ebb565b60008181526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16156151465760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610ebb565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020526040812080546001929061517c908490615b5c565b909155505060008181526003602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115615236575060009050600361530e565b8460ff16601b1415801561524e57508460ff16601c14155b1561525f575060009050600461530e565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156152b3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166153075760006001925092505061530e565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660ff84901c601b01615351878288856151ff565b935093505050935093915050565b82805461536b90615a1b565b90600052602060002090601f01602090048101928261538d57600085556153f1565b82601f106153c4578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556153f1565b828001600101855582156153f1579182015b828111156153f15782358255916020019190600101906153d6565b506153fd929150615475565b5090565b82805461540d90615a1b565b90600052602060002090601f01602090048101928261542f57600085556153f1565b82601f1061544857805160ff19168380011785556153f1565b828001600101855582156153f1579182015b828111156153f157825182559160200191906001019061545a565b5b808211156153fd5760008155600101615476565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461295b57600080fd5b6000602082840312156154ca57600080fd5b8135613beb8161548a565b60005b838110156154f05781810151838201526020016154d8565b838111156131bd5750506000910152565b600081518084526155198160208601602086016154d5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000613beb6020830184615501565b801515811461295b57600080fd5b60006020828403121561557e57600080fd5b8135613beb8161555e565b60006020828403121561559b57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461295b57600080fd5b600080604083850312156155d757600080fd5b82356155e2816155a2565b946020939093013593505050565b60008083601f84011261560257600080fd5b50813567ffffffffffffffff81111561561a57600080fd5b6020830191508360208260051b850101111561171357600080fd5b6000806020838503121561564857600080fd5b823567ffffffffffffffff81111561565f57600080fd5b61566b858286016155f0565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600067ffffffffffffffff808411156156c1576156c1615677565b604051601f85017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561570757615707615677565b8160405280935085815286868601111561572057600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261574b57600080fd5b613beb838335602085016156a6565b6000806000806080858703121561577057600080fd5b843561577b816155a2565b9350602085013561578b816155a2565b925060408501359150606085013567ffffffffffffffff8111156157ae57600080fd5b6157ba8782880161573a565b91505092959194509250565b6000602082840312156157d857600080fd5b8135613beb816155a2565b6000806000606084860312156157f857600080fd5b8335615803816155a2565b92506020840135615813816155a2565b929592945050506040919091013590565b6000806040838503121561583757600080fd5b50508035926020909101359150565b6000806000806040858703121561585c57600080fd5b843567ffffffffffffffff8082111561587457600080fd5b615880888389016155f0565b9096509450602087013591508082111561589957600080fd5b506158a6878288016155f0565b95989497509550505050565b600080602083850312156158c557600080fd5b823567ffffffffffffffff808211156158dd57600080fd5b818501915085601f8301126158f157600080fd5b81358181111561590057600080fd5b86602082850101111561591257600080fd5b60209290920196919550909350505050565b6000806040838503121561593757600080fd5b8235615942816155a2565b915060208301356159528161555e565b809150509250929050565b60006020828403121561596f57600080fd5b813567ffffffffffffffff81111561598657600080fd5b8201601f8101841361599757600080fd5b6113e8848235602084016156a6565b600080604083850312156159b957600080fd5b82359150602083013567ffffffffffffffff8111156159d757600080fd5b6159e38582860161573a565b9150509250929050565b60008060408385031215615a0057600080fd5b8235615a0b816155a2565b91506020830135615952816155a2565b600181811c90821680615a2f57607f821691505b60208210811415615a69577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600060208284031215615a8157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615b1857615b18615ab7565b5060010190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615b5757615b57615ab7565b500290565b60008219821115615b6f57615b6f615ab7565b500190565b600082821015615b8657615b86615ab7565b500390565b600060208284031215615b9d57600080fd5b8151613beb8161555e565b8054600090600181811c9080831680615bc257607f831692505b6020808410821415615bfd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b818015615c115760018114615c4057615c6d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861689528489019650615c6d565b60008881526020902060005b86811015615c655781548b820152908501908301615c4c565b505084890196505b50505050505092915050565b6000615c858288615ba8565b8651615c95818360208b016154d5565b8651910190615ca8818360208a016154d5565b8551910190615cbb8183602089016154d5565b8451910190615cce8183602088016154d5565b01979650505050505050565b600060208284031215615cec57600080fd5b8151613beb816155a2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615d3557615d35615cf7565b500490565b600082615d4957615d49615cf7565b500690565b6000615d63615d5d8387615ba8565b85615ba8565b60609390931b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000168352505060140192915050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152615dd76080830184615501565b9695505050505050565b600060208284031215615df357600080fd5b8151613beb8161548a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220aced6b5fac40f572f2cbeefbbfa8e32bedbe94eb87324054954035292f3691c364736f6c63430008090033

Deployed Bytecode Sourcemap

104162:10210:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55501:36;;;;;;;;;;;;;;;;;;;160:25:1;;;148:2;133:18;55501:36:0;;;;;;;;56870:219;;;;;;;;;;-1:-1:-1;56870:219:0;;;;;:::i;:::-;;:::i;:::-;;;793:14:1;;786:22;768:41;;756:2;741:18;56870:219:0;628:187:1;22391:100:0;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;110152:109::-;;;;;;;;;;-1:-1:-1;110152:109:0;;;;;:::i;:::-;;:::i;:::-;;23950:221;;;;;;;;;;-1:-1:-1;23950:221:0;;;;;:::i;:::-;;:::i;:::-;;;2360:42:1;2348:55;;;2330:74;;2318:2;2303:18;23950:221:0;2184:226:1;23473:411:0;;;;;;;;;;-1:-1:-1;23473:411:0;;;;;:::i;:::-;;:::i;111662:440::-;;;;;;;;;;-1:-1:-1;111662:440:0;;;;;:::i;:::-;;:::i;103364:207::-;;;;;;;;;;-1:-1:-1;103364:207:0;;;;;:::i;:::-;;:::i;:::-;;;5661:66:1;5649:79;;;5631:98;;5619:2;5604:18;103364:207:0;5487:248:1;104654:29:0;;;;;;;;;;;;;;;;59697:120;;;;;;;;;;-1:-1:-1;59697:120:0;;;;;:::i;:::-;;:::i;104560:38::-;;;;;;;;;;-1:-1:-1;104560:38:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;62200:182;;;;;;;;;;-1:-1:-1;62200:182:0;;;;;:::i;:::-;;:::i;24840:339::-;;;;;;;;;;-1:-1:-1;24840:339:0;;;;;:::i;:::-;;:::i;55427:28::-;;;;;;;;;;;;;:::i;61330:293::-;;;;;;;;;;-1:-1:-1;61330:293:0;;;;;:::i;:::-;;:::i;:::-;;;;6910:42:1;6898:55;;;6880:74;;6985:2;6970:18;;6963:34;;;;6853:18;61330:293:0;6706:297:1;112661:1708:0;;;;;;;;;;-1:-1:-1;112661:1708:0;;;;;:::i;:::-;;:::i;59876:128::-;;;;;;;;;;-1:-1:-1;59876:128:0;;;;;:::i;:::-;;:::i;55394:26::-;;;;;;;;;;;;;:::i;25250:185::-;;;;;;;;;;-1:-1:-1;25250:185:0;;;;;:::i;:::-;;:::i;61709:124::-;;;;;;;;;;;;;:::i;109768:32::-;;;;;;;;;;-1:-1:-1;109768:32:0;;;;;;;;;;;59355:142;;;;;;;;;;-1:-1:-1;59355:142:0;;;;;:::i;:::-;;:::i;112157:443::-;;;;;;;;;;-1:-1:-1;112157:443:0;;;;;:::i;:::-;;:::i;55656:47::-;;;;;;;;;;-1:-1:-1;55656:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;55462:32;;;;;;;;;;;;;;;;104374:40;;;;;;;;;;;;;;;;22085:239;;;;;;;;;;-1:-1:-1;22085:239:0;;;;;:::i;:::-;;:::i;109555:43::-;;;;;;;;;;-1:-1:-1;109555:43:0;;;;;;;;21815:208;;;;;;;;;;-1:-1:-1;21815:208:0;;;;;:::i;:::-;;:::i;36296:94::-;;;;;;;;;;;;;:::i;110780:448::-;;;;;;;;;;-1:-1:-1;110780:448:0;;;;;:::i;:::-;;:::i;109669:26::-;;;;;;;;;;-1:-1:-1;109669:26:0;;;;;;;;;;;106827:195;;;;;;;;;;-1:-1:-1;106827:195:0;;;;;:::i;:::-;;:::i;35645:87::-;;;;;;;;;;-1:-1:-1;35691:7:0;35718:6;;;35645:87;;105622:249;;;;;;;;;;-1:-1:-1;105622:249:0;;;;;:::i;:::-;;:::i;110561:149::-;;;;;;;;;;-1:-1:-1;110561:149:0;;;;;:::i;:::-;;:::i;59544:94::-;;;;;;;;;;-1:-1:-1;59544:94:0;;;;;:::i;:::-;;:::i;58555:101::-;;;;;;;;;;;;;:::i;22560:104::-;;;;;;;;;;;;;:::i;61179:114::-;;;;;;;;;;-1:-1:-1;61179:114:0;;;;;:::i;:::-;;:::i;55783:29::-;;;;;;;;;;;;;;;;55575:20;;;;;;;;;;;;;;;;60429:125;;;;;;;;;;-1:-1:-1;60429:125:0;;;;;:::i;:::-;;:::i;24243:295::-;;;;;;;;;;-1:-1:-1;24243:295:0;;;;;:::i;:::-;;:::i;108903:609::-;;;;;;;;;;-1:-1:-1;108903:609:0;;;;;:::i;:::-;;:::i;60074:94::-;;;;;;;;;;-1:-1:-1;60074:94:0;;;;;:::i;:::-;;:::i;25506:328::-;;;;;;;;;;-1:-1:-1;25506:328:0;;;;;:::i;:::-;;:::i;55629:20::-;;;;;;;;;;-1:-1:-1;55629:20:0;;;;;;;;;;;107095:560;;;;;;;;;;-1:-1:-1;107095:560:0;;;;;:::i;:::-;;:::i;60242:140::-;;;;;;;;;;-1:-1:-1;60242:140:0;;;;;:::i;:::-;;:::i;55819:35::-;;;;;;;;;;-1:-1:-1;55819:35:0;;;;;;;;62451:292;;;;;;;;;;-1:-1:-1;62451:292:0;;;;;:::i;:::-;;:::i;55361:26::-;;;;;;;;;;;;;:::i;109991:97::-;;;;;;;;;;-1:-1:-1;109991:97:0;;;;;:::i;:::-;;:::i;58714:154::-;;;;;;;;;;;;;:::i;108268:589::-;;;;;;:::i;:::-;;:::i;107733:465::-;;;;;;:::i;:::-;;:::i;55602:20::-;;;;;;;;;;-1:-1:-1;55602:20:0;;;;;;;;60621:122;;;;;;;;;;-1:-1:-1;60621:122:0;;;;;:::i;:::-;;:::i;55544:24::-;;;;;;;;;;;;;;;;55749:27;;;;;;;;;;-1:-1:-1;55749:27:0;;;;;;;;62836:435;;;;;;;;;;-1:-1:-1;62836:435:0;;;;;:::i;:::-;;:::i;55710:32::-;;;;;;;;;;-1:-1:-1;55710:32:0;;;;;;;;36545:192;;;;;;;;;;-1:-1:-1;36545:192:0;;;;;:::i;:::-;;:::i;61897:239::-;;;;;;;;;;-1:-1:-1;61897:239:0;;;;;:::i;:::-;;:::i;105374:171::-;;;;;;;;;;-1:-1:-1;105374:171:0;;;;;:::i;:::-;;:::i;110301:132::-;;;;;;;;;;-1:-1:-1;110301:132:0;;;;;:::i;:::-;;:::i;59164:142::-;;;;;;;;;;-1:-1:-1;59164:142:0;;;;;:::i;:::-;;:::i;104466:38::-;;;;;;;;;;-1:-1:-1;104466:38:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;56870:219;56974:4;56998:42;;;57014:26;56998:42;;:83;;;57044:37;57068:12;57044:23;:37::i;:::-;56991:90;56870:219;-1:-1:-1;;56870:219:0:o;22391:100::-;22445:13;22478:5;22471:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22391:100;:::o;110152:109::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;;;;;;;;;110225:20:::1;:28:::0;;;::::1;;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;110152:109::o;23950:221::-;24026:7;27433:16;;;:7;:16;;;;;;:30;:16;24046:73;;;;-1:-1:-1;;;24046:73:0;;12382:2:1;24046:73:0;;;12364:21:1;12421:2;12401:18;;;12394:30;12460:34;12440:18;;;12433:62;12531:14;12511:18;;;12504:42;12563:19;;24046:73:0;12180:408:1;24046:73:0;-1:-1:-1;24139:24:0;;;;:15;:24;;;;;;;;;23950:221::o;23473:411::-;23554:13;23570:23;23585:7;23570:14;:23::i;:::-;23554:39;;23618:5;23612:11;;:2;:11;;;;23604:57;;;;-1:-1:-1;;;23604:57:0;;12795:2:1;23604:57:0;;;12777:21:1;12834:2;12814:18;;;12807:30;12873:34;12853:18;;;12846:62;12944:3;12924:18;;;12917:31;12965:19;;23604:57:0;12593:397:1;23604:57:0;16395:10;23696:21;;;;;:62;;-1:-1:-1;23721:37:0;23738:5;16395:10;62836:435;:::i;23721:37::-;23674:168;;;;-1:-1:-1;;;23674:168:0;;13197:2:1;23674:168:0;;;13179:21:1;13236:2;13216:18;;;13209:30;13275:34;13255:18;;;13248:62;13346:26;13326:18;;;13319:54;13390:19;;23674:168:0;12995:420:1;23674:168:0;23855:21;23864:2;23868:7;23855:8;:21::i;:::-;23543:341;23473:411;;:::o;111662:440::-;109864:15;;109856:38;109864:15;109848:61;;;;-1:-1:-1;;;109848:61:0;;13622:2:1;109848:61:0;;;13604:21:1;13661:2;13641:18;;;13634:30;13700:12;13680:18;;;13673:40;13730:18;;109848:61:0;13420:334:1;109848:61:0;111748:20:::1;::::0;;;::::1;;;111740:41;;;::::0;-1:-1:-1;;;111740:41:0;;13961:2:1;111740:41:0::1;::::0;::::1;13943:21:1::0;14000:1;13980:18;;;13973:29;14038:10;14018:18;;;14011:38;14066:18;;111740:41:0::1;13759:331:1::0;111740:41:0::1;111800:15;::::0;:40:::1;::::0;;;;111826:10:::1;111800:40;::::0;::::1;6880:74:1::0;111838:1:0::1;6970:18:1::0;;;6963:34;111844:9:0;;111800:15:::1;;::::0;:25:::1;::::0;6853:18:1;;111800:40:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:60;;111792:80;;;::::0;-1:-1:-1;;;111792:80:0;;14796:2:1;111792:80:0::1;::::0;::::1;14778:21:1::0;14835:1;14815:18;;;14808:29;14873:9;14853:18;;;14846:37;14900:18;;111792:80:0::1;14594:330:1::0;111792:80:0::1;111883:24;111897:9;;111883:13;:24::i;:::-;-1:-1:-1::0;111920:15:0::1;::::0;:61:::1;::::0;;;;111949:10:::1;111920:61;::::0;::::1;15139:74:1::0;111961:1:0::1;15229:18:1::0;;;15222:34;15272:18;;;15265:34;;;111920:15:0::1;::::0;;::::1;::::0;:28:::1;::::0;15112:18:1;;111920:61:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;111999:10;111994:101;112015:21:::0;;::::1;111994:101;;;112059:24;112069:9;;112079:2;112069:13;;;;;;;:::i;:::-;;;;;;;112059:9;:24::i;:::-;112038:4:::0;::::1;::::0;::::1;:::i;:::-;;;;111994:101;;103364:207:::0;103533:30;103364:207;;;;;;;:::o;59697:120::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;59782:17:::1;:27:::0;59697:120::o;62200:182::-;55952:17;;:31;:17;55944:58;;;;-1:-1:-1;;;55944:58:0;;16090:2:1;55944:58:0;;;16072:21:1;16129:2;16109:18;;;16102:30;16168:16;16148:18;;;16141:44;16202:18;;55944:58:0;15888:338:1;55944:58:0;56021:17;;:33;:17;16395:10;56021:33;56013:57;;;;-1:-1:-1;;;56013:57:0;;16433:2:1;56013:57:0;;;16415:21:1;16472:2;16452:18;;;16445:30;16511:13;16491:18;;;16484:41;16542:18;;56013:57:0;16231:335:1;56013:57:0;62291:17:::1;:28:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;62200:182::o;24840:339::-;25035:41;16395:10;25068:7;25035:18;:41::i;:::-;25027:103;;;;-1:-1:-1;;;25027:103:0;;16773:2:1;25027:103:0;;;16755:21:1;16812:2;16792:18;;;16785:30;16851:34;16831:18;;;16824:62;16922:19;16902:18;;;16895:47;16959:19;;25027:103:0;16571:413:1;25027:103:0;25143:28;25153:4;25159:2;25163:7;25143:9;:28::i;55427:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;61330:293::-;61429:16;27433;;;:7;:16;;;;;;61429;;27433:30;:16;61481:38;;;;-1:-1:-1;;;61481:38:0;;17191:2:1;61481:38:0;;;17173:21:1;17230:1;17210:18;;;17203:29;17268:10;17248:18;;;17241:38;17296:18;;61481:38:0;16989:331:1;61481:38:0;61548:4;61555:59;61568:40;61581:10;61593:14;;61568:12;:40::i;:::-;61610:3;61555:12;:59::i;:::-;61532:83;;;;61330:293;;;;;;:::o;112661:1708::-;109864:15;;109856:38;109864:15;109848:61;;;;-1:-1:-1;;;109848:61:0;;13622:2:1;109848:61:0;;;13604:21:1;13661:2;13641:18;;;13634:30;13700:12;13680:18;;;13673:40;13730:18;;109848:61:0;13420:334:1;109848:61:0;112773:14:::1;::::0;;;::::1;;;112765:35;;;::::0;-1:-1:-1;;;112765:35:0;;13961:2:1;112765:35:0::1;::::0;::::1;13943:21:1::0;14000:1;13980:18;;;13973:29;14038:10;14018:18;;;14011:38;14066:18;;112765:35:0::1;13759:331:1::0;112765:35:0::1;112819:19:::0;112811:40:::1;;;::::0;-1:-1:-1;;;112811:40:0;;17527:2:1;112811:40:0::1;::::0;::::1;17509:21:1::0;17566:1;17546:18;;;17539:29;17604:10;17584:18;;;17577:38;17632:18;;112811:40:0::1;17325:331:1::0;112811:40:0::1;112870:35:::0;;::::1;112862:63;;;::::0;-1:-1:-1;;;112862:63:0;;17863:2:1;112862:63:0::1;::::0;::::1;17845:21:1::0;17902:2;17882:18;;;17875:30;17941:17;17921:18;;;17914:45;17976:18;;112862:63:0::1;17661:339:1::0;112862:63:0::1;112962:1;112944:19:::0;::::1;112936:45;;;::::0;-1:-1:-1;;;112936:45:0;;18207:2:1;112936:45:0::1;::::0;::::1;18189:21:1::0;18246:2;18226:18;;;18219:30;18285:15;18265:18;;;18258:43;18318:18;;112936:45:0::1;18005:337:1::0;112936:45:0::1;112999:10;112994:328;113015:20:::0;;::::1;112994:328;;;113082:1;113066:9;;113076:2;113066:13;;;;;;;:::i;:::-;;;;;;;:17;113058:43;;;::::0;-1:-1:-1;;;113058:43:0;;18549:2:1;113058:43:0::1;::::0;::::1;18531:21:1::0;18588:2;18568:18;;;18561:30;18627:15;18607:18;;;18600:43;18660:18;;113058:43:0::1;18347:337:1::0;113058:43:0::1;113229:9;;113239:2;113229:13;;;;;;;:::i;:::-;113174:15;::::0;113229:13:::1;::::0;;::::1;::::0;;;::::1;;::::0;113174:15:::1;;::::0;-1:-1:-1;113174:25:0::1;113200:10;113212:8:::0;;113221:2;113212:12;;::::1;;;;;:::i;:::-;113174:51;::::0;;::::1;::::0;;;;;;6910:42:1;6898:55;;;113174:51:0::1;::::0;::::1;6880:74:1::0;113212:12:0::1;;::::0;;;::::1;;6970:18:1::0;;;6963:34;-1:-1:-1;6853:18:1;;113174:51:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:68;;113166:88;;;::::0;-1:-1:-1;;;113166:88:0;;14796:2:1;113166:88:0::1;::::0;::::1;14778:21:1::0;14835:1;14815:18;;;14808:29;14873:9;14853:18;;;14846:37;14900:18;;113166:88:0::1;14594:330:1::0;113166:88:0::1;113292:1;113277:8;;113286:2;113277:12;;;;;;;:::i;:::-;;;;;;;:16;113269:41;;;::::0;-1:-1:-1;;;113269:41:0;;18891:2:1;113269:41:0::1;::::0;::::1;18873:21:1::0;18930:2;18910:18;;;18903:30;18969:14;18949:18;;;18942:42;19001:18;;113269:41:0::1;18689:336:1::0;113269:41:0::1;113037:4:::0;::::1;::::0;::::1;:::i;:::-;;;;112994:328;;;-1:-1:-1::0;113334:20:0::1;::::0;113365:806:::1;113386:20:::0;;::::1;113365:806;;;113477:15;::::0;::::1;;:28;113506:10;113518:8:::0;;113527:2;113518:12;;::::1;;;;;:::i;:::-;;;;;;;113532:9;;113542:2;113532:13;;;;;;;:::i;:::-;113477:69;::::0;;::::1;::::0;;;;;;15169:42:1;15157:55;;;113477:69:0::1;::::0;::::1;15139:74:1::0;15229:18;;;15222:34;;;;-1:-1:-1;113532:13:0::1;::::0;;::::1;;;15272:18:1::0;;;15265:34;15112:18;;113477:69:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;113702:9;;113712:2;113702:13;;;;;;;:::i;:::-;113643:15;::::0;113702:13:::1;::::0;;::::1;::::0;;;::::1;;::::0;113643:15:::1;;::::0;-1:-1:-1;113643:42:0::1;113686:8:::0;;113695:2;113686:12;;::::1;;;;;:::i;:::-;;;;;;;113643:56;;;;;;;;;;;;;160:25:1::0;;148:2;133:18;;14:177;113643:56:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:72;;;;:::i;:::-;113627:88;::::0;;::::1;:::i;:::-;;;113804:8;;113813:2;113804:12;;;;;;;:::i;:::-;;;;;;;113820:1;113804:17;113800:360;;;113842:15;::::0;::::1;;:28;113871:10;113883:1;113886:9:::0;;113896:2;113886:13;;::::1;;;;;:::i;:::-;113842:58;::::0;;::::1;::::0;;;;;;15169:42:1;15157:55;;;113842:58:0::1;::::0;::::1;15139:74:1::0;15229:18;;;15222:34;;;;-1:-1:-1;113886:13:0::1;::::0;;::::1;;;15272:18:1::0;;;15265:34;15112:18;;113842:58:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;113800:360;;;113926:8;;113935:2;113926:12;;;;;;;:::i;:::-;;;;;;;113942:1;113926:17;113922:238;;;113964:15;::::0;::::1;;:28;113993:10;114005:1;114008:9:::0;;114018:2;114008:13;;::::1;;;;;:::i;113922:238::-;114048:8;;114057:2;114048:12;;;;;;;:::i;:::-;;;;;;;114064:1;114048:17;114044:116;;;114086:15;::::0;::::1;;:31;114118:10;114130:9:::0;;114140:2;114130:13;;::::1;;;;;:::i;:::-;114086:58;::::0;;::::1;::::0;;;;;;6910:42:1;6898:55;;;114086:58:0::1;::::0;::::1;6880:74:1::0;114130:13:0::1;;::::0;;;::::1;;6970:18:1::0;;;6963:34;-1:-1:-1;6853:18:1;;114086:58:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;114044:116;113408:4:::0;::::1;::::0;::::1;:::i;:::-;;;;113365:806;;;;114206:12;114183:19;;:35;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;114281:9:0::1;::::0;-1:-1:-1;114276:86:0::1;114300:12;114296:1;:16;114276:86;;;114334:16;114339:10;114334:4;:16::i;:::-;114314:3:::0;::::1;::::0;::::1;:::i;:::-;;;;114276:86;;;;112754:1615;112661:1708:::0;;;;:::o;59876:128::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;59965:21:::1;:31:::0;59876:128::o;55394:26::-;;;;;;;:::i;25250:185::-;25388:39;25405:4;25411:2;25415:7;25388:39;;;;;;;;;;;;:16;:39::i;61709:124::-;55952:17;;61777:7;;55952:31;:17;55944:58;;;;-1:-1:-1;;;55944:58:0;;16090:2:1;55944:58:0;;;16072:21:1;16129:2;16109:18;;;16102:30;16168:16;16148:18;;;16141:44;16202:18;;55944:58:0;15888:338:1;55944:58:0;56021:17;;:33;:17;16395:10;56021:33;56013:57;;;;-1:-1:-1;;;56013:57:0;;16433:2:1;56013:57:0;;;16415:21:1;16472:2;16452:18;;;16445:30;16511:13;16491:18;;;16484:41;16542:18;;56013:57:0;16231:335:1;56013:57:0;-1:-1:-1;61804:21:0::1;61709:124:::0;:::o;59355:142::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;59428:8:::1;:18:::0;;;::::1;;;;::::0;;;::::1;;::::0;;59462:27:::1;::::0;::::1;::::0;::::1;::::0;20482:2:1;20464:21;;;20521:1;20501:18;;;20494:29;20559:10;20554:2;20539:18;;20532:38;20602:2;20587:18;;20280:331;59462:27:0::1;;;;;;;;59355:142:::0;:::o;112157:443::-;109864:15;;109856:38;109864:15;109848:61;;;;-1:-1:-1;;;109848:61:0;;13622:2:1;109848:61:0;;;13604:21:1;13661:2;13641:18;;;13634:30;13700:12;13680:18;;;13673:40;13730:18;;109848:61:0;13420:334:1;109848:61:0;112244:20:::1;::::0;;;::::1;;;112236:41;;;::::0;-1:-1:-1;;;112236:41:0;;13961:2:1;112236:41:0::1;::::0;::::1;13943:21:1::0;14000:1;13980:18;;;13973:29;14038:10;14018:18;;;14011:38;14066:18;;112236:41:0::1;13759:331:1::0;112236:41:0::1;112296:15;::::0;:40:::1;::::0;;;;112322:10:::1;112296:40;::::0;::::1;6880:74:1::0;112334:1:0::1;6970:18:1::0;;;6963:34;112340:9:0;;112296:15:::1;;::::0;:25:::1;::::0;6853:18:1;;112296:40:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:60;;112288:80;;;::::0;-1:-1:-1;;;112288:80:0;;14796:2:1;112288:80:0::1;::::0;::::1;14778:21:1::0;14835:1;14815:18;;;14808:29;14873:9;14853:18;;;14846:37;14900:18;;112288:80:0::1;14594:330:1::0;112288:80:0::1;112379:24;112393:9;;112379:13;:24::i;:::-;-1:-1:-1::0;112416:15:0::1;::::0;:61:::1;::::0;;;;112445:10:::1;112416:61;::::0;::::1;15139:74:1::0;112457:1:0::1;15229:18:1::0;;;15222:34;15272:18;;;15265:34;;;112416:15:0::1;::::0;;::::1;::::0;:28:::1;::::0;15112:18:1;;112416:61:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;112495:10;112490:103;112511:21:::0;;::::1;112490:103;;;112555:26;112567:9;;112577:2;112567:13;;;;;;;:::i;:::-;;;;;;;112555:11;:26::i;:::-;112534:4:::0;::::1;::::0;::::1;:::i;:::-;;;;112490:103;;22085:239:::0;22157:7;22193:16;;;:7;:16;;;;;;;;22228:19;22220:73;;;;-1:-1:-1;;;22220:73:0;;21128:2:1;22220:73:0;;;21110:21:1;21167:2;21147:18;;;21140:30;21206:34;21186:18;;;21179:62;21277:11;21257:18;;;21250:39;21306:19;;22220:73:0;20926:405:1;21815:208:0;21887:7;21915:19;;;21907:74;;;;-1:-1:-1;;;21907:74:0;;21538:2:1;21907:74:0;;;21520:21:1;21577:2;21557:18;;;21550:30;21616:34;21596:18;;;21589:62;21687:12;21667:18;;;21660:40;21717:19;;21907:74:0;21336:406:1;21907:74:0;-1:-1:-1;21999:16:0;;;;;;:9;:16;;;;;;;21815:208::o;36296:94::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;36361:21:::1;36379:1;36361:9;:21::i;:::-;36296:94::o:0;110780:448::-;109864:15;;109856:38;109864:15;109848:61;;;;-1:-1:-1;;;109848:61:0;;13622:2:1;109848:61:0;;;13604:21:1;13661:2;13641:18;;;13634:30;13700:12;13680:18;;;13673:40;13730:18;;109848:61:0;13420:334:1;109848:61:0;110860:20:::1;::::0;;;::::1;;;110852:41;;;::::0;-1:-1:-1;;;110852:41:0;;13961:2:1;110852:41:0::1;::::0;::::1;13943:21:1::0;14000:1;13980:18;;;13973:29;14038:10;14018:18;;;14011:38;14066:18;;110852:41:0::1;13759:331:1::0;110852:41:0::1;110912:15;::::0;:33:::1;::::0;;;;::::1;::::0;::::1;160:25:1::0;;;110912:15:0::1;::::0;;::::1;::::0;:28:::1;::::0;133:18:1;;110912:33:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;110904:56;;;::::0;-1:-1:-1;;;110904:56:0;;22199:2:1;110904:56:0::1;::::0;::::1;22181:21:1::0;22238:2;22218:18;;;22211:30;22277:12;22257:18;;;22250:40;22307:18;;110904:56:0::1;21997:334:1::0;110904:56:0::1;110979:15;::::0;:42:::1;::::0;;;;111005:10:::1;110979:42;::::0;::::1;6880:74:1::0;6970:18;;;6963:34;;;111025:1:0::1;::::0;110979:15:::1;;::::0;:25:::1;::::0;6853:18:1;;110979:42:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;110971:70;;;::::0;-1:-1:-1;;;110971:70:0;;22538:2:1;110971:70:0::1;::::0;::::1;22520:21:1::0;22577:2;22557:18;;;22550:30;22616:12;22596:18;;;22589:40;22646:18;;110971:70:0::1;22336:334:1::0;110971:70:0::1;111084:15;::::0;:48:::1;::::0;;;;111113:10:::1;111084:48;::::0;::::1;15139:74:1::0;15229:18;;;15222:34;;;111084:15:0;15272:18:1;;;15265:34;111084:15:0::1;::::0;;::::1;::::0;:28:::1;::::0;15112:18:1;;111084:48:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;111195:25;111209:10;111195:13;:25::i;:::-;110780:448:::0;:::o;106827:195::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;106921:9:::1;106916:99;106936:20:::0;;::::1;106916:99;;;106978:25;106990:9;;107000:1;106990:12;;;;;;;:::i;106978:25::-;106958:3:::0;::::1;::::0;::::1;:::i;:::-;;;;106916:99;;105622:249:::0;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;105723:9:::1;;105713:7;:19;105705:45;;;::::0;-1:-1:-1;;;105705:45:0;;23258:2:1;105705:45:0::1;::::0;::::1;23240:21:1::0;23297:2;23277:18;;;23270:30;23336:15;23316:18;;;23309:43;23369:18;;105705:45:0::1;23056:337:1::0;105705:45:0::1;105801:11;:9;:11::i;:::-;105779:19;;:33;;;;:::i;:::-;105769:7;:43;105761:72;;;::::0;-1:-1:-1;;;105761:72:0;;23600:2:1;105761:72:0::1;::::0;::::1;23582:21:1::0;23639:2;23619:18;;;23612:30;23678:18;23658;;;23651:46;23714:18;;105761:72:0::1;23398:340:1::0;105761:72:0::1;105844:9;:19:::0;105622:249::o;110561:149::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;109864:15:::1;::::0;109856:38:::1;109864:15;109848:61;;;::::0;-1:-1:-1;;;109848:61:0;;13622:2:1;109848:61:0::1;::::0;::::1;13604:21:1::0;13661:2;13641:18;;;13634:30;13700:12;13680:18;;;13673:40;13730:18;;109848:61:0::1;13420:334:1::0;109848:61:0::1;110660:15:::2;::::0;:42:::2;::::0;;;;:15:::2;6898:55:1::0;;;110660:42:0::2;::::0;::::2;6880:74:1::0;6970:18;;;6963:34;;;110660:15:0;;::::2;::::0;:31:::2;::::0;6853:18:1;;110660:42:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;59544:94:::0;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;59616:5:::1;:14:::0;59544:94::o;58555:101::-;58597:7;58624:24;:14;37848;;37756:114;58624:24;58617:31;;58555:101;:::o;22560:104::-;22616:13;22649:7;22642:14;;;;;:::i;61179:114::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;61261:14:::1;:24:::0;61179:114::o;60429:125::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;60518:28:::1;:12;60533:13:::0;;60518:28:::1;:::i;24243:295::-:0;24346:24;;;16395:10;24346:24;;24338:62;;;;-1:-1:-1;;;24338:62:0;;23945:2:1;24338:62:0;;;23927:21:1;23984:2;23964:18;;;23957:30;24023:27;24003:18;;;23996:55;24068:18;;24338:62:0;23743:349:1;24338:62:0;16395:10;24413:32;;;;:18;:32;;;;;;;;;:42;;;;;;;;;;;;:53;;;;;;;;;;;;;24482:48;;768:41:1;;;24413:42:0;;16395:10;24482:48;;741:18:1;24482:48:0;;;;;;;24243:295;;:::o;108903:609::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;109024:36;;::::1;109016:64;;;::::0;-1:-1:-1;;;109016:64:0;;24299:2:1;109016:64:0::1;::::0;::::1;24281:21:1::0;24338:2;24318:18;;;24311:30;24377:17;24357:18;;;24350:45;24412:18;;109016:64:0::1;24097:339:1::0;109016:64:0::1;109093:13;::::0;109117:93:::1;109137:19:::0;;::::1;109117:93;;;109187:8;;109196:1;109187:11;;;;;;;:::i;:::-;;;;;;;109178:20;;;;;:::i;:::-;::::0;-1:-1:-1;109158:3:0;::::1;::::0;::::1;:::i;:::-;;;;109117:93;;;;109275:9;;109252:19;;109244:5;109230:11;:9;:11::i;:::-;:19;;;;:::i;:::-;:41;;;;:::i;:::-;:54;;109222:75;;;::::0;-1:-1:-1;;;109222:75:0;;24643:2:1;109222:75:0::1;::::0;::::1;24625:21:1::0;24682:1;24662:18;;;24655:29;24720:10;24700:18;;;24693:38;24748:18;;109222:75:0::1;24441:331:1::0;109222:75:0::1;-1:-1:-1::0;109310:12:0::1;::::0;109335:170:::1;109355:21:::0;;::::1;109335:170;;;109403:9;109398:96;109422:8;;109431:1;109422:11;;;;;;;:::i;:::-;;;;;;;109418:1;:15;109398:96;;;109459:19;109464:10;;109475:1;109464:13;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;109459:4;:19::i;:::-;109435:3:::0;::::1;::::0;::::1;:::i;:::-;;;;109398:96;;;-1:-1:-1::0;109378:3:0;::::1;::::0;::::1;:::i;:::-;;;;109335:170;;60074:94:::0;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;60150:10:::1;:3;60156:4:::0;;60150:10:::1;:::i;25506:328::-:0;25681:41;16395:10;25714:7;25681:18;:41::i;:::-;25673:103;;;;-1:-1:-1;;;25673:103:0;;16773:2:1;25673:103:0;;;16755:21:1;16812:2;16792:18;;;16785:30;16851:34;16831:18;;;16824:62;16922:19;16902:18;;;16895:47;16959:19;;25673:103:0;16571:413:1;25673:103:0;25787:39;25801:4;25807:2;25811:7;25820:5;25787:13;:39::i;:::-;25506:328;;;;:::o;107095:560::-;27409:4;27433:16;;;:7;:16;;;;;;107161:13;;27433:30;:16;107187:38;;;;-1:-1:-1;;;107187:38:0;;17191:2:1;107187:38:0;;;17173:21:1;17230:1;17210:18;;;17203:29;17268:10;17248:18;;;17241:38;17296:18;;107187:38:0;16989:331:1;107187:38:0;107238:36;;;;;;;;;;;;;;;;;;;;107285:25;;;;;;;107238:20;107285:25;;;107325:16;;;:6;:16;;;;;;;107238:36;;107285:25;107325:16;;107321:68;;;-1:-1:-1;107358:19:0;;;;;;;;;;;;;;;;;107321:68;107399:26;;;;;;;;;:21;:26;;;107440:16;;;:6;:16;;;;;;;;;;107436:70;;;-1:-1:-1;107473:21:0;;;;;;;;;;;;;;;;;107436:70;107554:1;107531:12;107525:26;;;;;:::i;:::-;;;:30;:122;;;;;;;;;;;;;;;;;107582:12;107596:19;:8;:17;:19::i;:::-;107617:6;107625;107633:7;107565:76;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;107525:122;107518:129;107095:560;-1:-1:-1;;;;;107095:560:0:o;60242:140::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;60320:14;;::::1;::::0;:5:::1;::::0;:14:::1;::::0;::::1;::::0;::::1;:::i;:::-;;60350:24;;;;;27161:2:1::0;27143:21;;;27200:1;27180:18;;;27173:29;27238:7;27233:2;27218:18;;27211:35;27278:2;27263:18;;26959:328;62451:292:0;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;62706:20:::1;:29:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;62451:292::o;55361:26::-;;;;;;;:::i;109991:97::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;110058:14:::1;:22:::0;;;::::1;;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;109991:97::o;58714:154::-;58784:8;;58763:4;;58784:8;;;;;58780:53;;;-1:-1:-1;58816:5:0;;58714:154::o;58780:53::-;-1:-1:-1;58852:8:0;;;;;58714:154::o;108268:589::-;108416:9;;108393:19;;108383:7;108369:11;:9;:11::i;:::-;:21;;;;:::i;:::-;:43;;;;:::i;:::-;:56;;108361:77;;;;-1:-1:-1;;;108361:77:0;;24643:2:1;108361:77:0;;;24625:21:1;24682:1;24662:18;;;24655:29;24720:10;24700:18;;;24693:38;24748:18;;108361:77:0;24441:331:1;108361:77:0;108497:17;;16395:10;108457:26;;;;:12;:26;;;;;;:36;;108486:7;;108457:36;:::i;:::-;:57;;108449:80;;;;-1:-1:-1;;;108449:80:0;;27494:2:1;108449:80:0;;;27476:21:1;27533:2;27513:18;;;27506:30;27572:12;27552:18;;;27545:40;27602:18;;108449:80:0;27292:334:1;108449:80:0;108549:8;;;;;;;108548:9;108540:31;;;;-1:-1:-1;;;108540:31:0;;27833:2:1;108540:31:0;;;27815:21:1;27872:1;27852:18;;;27845:29;27910:11;27890:18;;;27883:39;27939:18;;108540:31:0;27631:332:1;108540:31:0;108590:27;108606:10;108590:15;:27::i;:::-;108582:57;;;;-1:-1:-1;;;108582:57:0;;28170:2:1;108582:57:0;;;28152:21:1;28209:2;28189:18;;;28182:30;28248:19;28228:18;;;28221:47;28285:18;;108582:57:0;27968:341:1;108582:57:0;108677:9;108666:7;108658:5;;:15;;;;:::i;:::-;:28;108650:56;;;;-1:-1:-1;;;108650:56:0;;28516:2:1;108650:56:0;;;28498:21:1;28555:2;28535:18;;;28528:30;28594:17;28574:18;;;28567:45;28629:18;;108650:56:0;28314:339:1;108650:56:0;16395:10;108719:26;;;;:12;:26;;;;;:37;;108749:7;;108719:26;:37;;108749:7;;108719:37;:::i;:::-;;;;-1:-1:-1;108772:9:0;;-1:-1:-1;108767:83:0;108791:7;108787:1;:11;108767:83;;;108820:18;16395:10;109459:4:::1;:19::i;108820:18::-:0;108800:3;;;;:::i;:::-;;;;108767:83;;107733:465;107856:9;;107833:19;;107823:7;107809:11;:9;:11::i;:::-;:21;;;;:::i;:::-;:43;;;;:::i;:::-;:56;;107801:77;;;;-1:-1:-1;;;107801:77:0;;24643:2:1;107801:77:0;;;24625:21:1;24682:1;24662:18;;;24655:29;24720:10;24700:18;;;24693:38;24748:18;;107801:77:0;24441:331:1;107801:77:0;107908:21;;107897:7;:32;;107889:57;;;;-1:-1:-1;;;107889:57:0;;28860:2:1;107889:57:0;;;28842:21:1;28899:2;28879:18;;;28872:30;28938:14;28918:18;;;28911:42;28970:18;;107889:57:0;28658:336:1;107889:57:0;107966:8;;;;;;;107965:9;107957:31;;;;-1:-1:-1;;;107957:31:0;;27833:2:1;107957:31:0;;;27815:21:1;27872:1;27852:18;;;27845:29;27910:11;27890:18;;;27883:39;27939:18;;107957:31:0;27631:332:1;107957:31:0;108007:8;;;;107999:31;;;;-1:-1:-1;;;107999:31:0;;29201:2:1;107999:31:0;;;29183:21:1;29240:2;29220:18;;;29213:30;29279:12;29259:18;;;29252:40;29309:18;;107999:31:0;28999:334:1;107999:31:0;108068:9;108057:7;108049:5;;:15;;;;:::i;:::-;:28;108041:56;;;;-1:-1:-1;;;108041:56:0;;28516:2:1;108041:56:0;;;28498:21:1;28555:2;28535:18;;;28528:30;28594:17;28574:18;;;28567:45;28629:18;;108041:56:0;28314:339:1;108041:56:0;108113:9;108108:83;108132:7;108128:1;:11;108108:83;;;108161:18;16395:10;109459:4:::1;:19::i;108161:18::-:0;108141:3;;;;:::i;:::-;;;;108108:83;;;;107733:465;:::o;60621:122::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;60707:12:::1;:28:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;60621:122::o;62836:435::-;62956:20;;62935:4;;62956:34;:20;:34;62952:251;;63052:20;;63100:30;;;;;63052:20;2348:55:1;;;63100:30:0;;;2330:74:1;63052:20:0;;;;63092:52;;;63052:20;;63100:22;;2303:18:1;;63100:30:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63092:52;;;63088:104;;;63172:4;63165:11;;;;;63088:104;62992:211;62952:251;24730:25;;;;24706:4;24730:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;63222:41;63215:48;62836:435;-1:-1:-1;;;62836:435:0:o;36545:192::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;36634:22:::1;::::0;::::1;36626:73;;;::::0;-1:-1:-1;;;36626:73:0;;29825:2:1;36626:73:0::1;::::0;::::1;29807:21:1::0;29864:2;29844:18;;;29837:30;29903:34;29883:18;;;29876:62;29974:8;29954:18;;;29947:36;30000:19;;36626:73:0::1;29623:402:1::0;36626:73:0::1;36710:19;36720:8;36710:9;:19::i;61897:239::-:0;55952:17;;61994:4;;55952:31;:17;55944:58;;;;-1:-1:-1;;;55944:58:0;;16090:2:1;55944:58:0;;;16072:21:1;16129:2;16109:18;;;16102:30;16168:16;16148:18;;;16141:44;16202:18;;55944:58:0;15888:338:1;55944:58:0;56021:17;;:33;:17;16395:10;56021:33;56013:57;;;;-1:-1:-1;;;56013:57:0;;16433:2:1;56013:57:0;;;16415:21:1;16472:2;16452:18;;;16445:30;16511:13;16491:18;;;16484:41;16542:18;;56013:57:0;16231:335:1;56013:57:0;62030:21:::1;62019:7;:32;;62011:63;;;::::0;-1:-1:-1;;;62011:63:0;;30232:2:1;62011:63:0::1;::::0;::::1;30214:21:1::0;30271:2;30251:18;;;30244:30;30310:20;30290:18;;;30283:48;30348:18;;62011:63:0::1;30030:342:1::0;62011:63:0::1;62085:21;::::0;:12:::1;::::0;::::1;::::0;:21;::::1;;;::::0;62098:7;;62085:21:::1;::::0;;;62098:7;62085:12;:21;::::1;;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;62124:4:0::1;::::0;61897:239;-1:-1:-1;;;61897:239:0:o;105374:171::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;105478:9:::1;;105470:4;105456:11;:9;:11::i;:::-;:18;;;;:::i;:::-;:31;;105448:52;;;::::0;-1:-1:-1;;;105448:52:0;;30579:2:1;105448:52:0::1;::::0;::::1;30561:21:1::0;30618:1;30598:18;;;30591:29;30656:10;30636:18;;;30629:38;30684:18;;105448:52:0::1;30377:331:1::0;105448:52:0::1;105511:19;:26:::0;105374:171::o;110301:132::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;110376:15:::1;:49:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;110301:132::o;59164:142::-;35691:7;35718:6;35865:23;35718:6;16395:10;35865:23;35857:68;;;;-1:-1:-1;;;35857:68:0;;12021:2:1;35857:68:0;;;12003:21:1;;;12040:18;;;12033:30;12099:34;12079:18;;;12072:62;12151:18;;35857:68:0;11819:356:1;35857:68:0;59237:8:::1;:18:::0;;;::::1;;::::0;;;::::1;;::::0;;59271:27:::1;::::0;::::1;::::0;::::1;::::0;30915:2:1;30897:21;;;30954:1;30934:18;;;30927:29;30992:10;30987:2;30972:18;;30965:38;31035:2;31020:18;;30713:331;37756:114:0;37848:14;;37756:114::o;37878:127::-;37967:19;;37985:1;37967:19;;;37878:127::o;8345:387::-;8668:20;8716:8;;;8345:387::o;21446:305::-;21548:4;21585:40;;;21600:25;21585:40;;:105;;-1:-1:-1;21642:48:0;;;21657:33;21642:48;21585:105;:158;;;-1:-1:-1;19619:25:0;19604:40;;;;21707:36;19495:157;31326:174;31401:24;;;;:15;:24;;;;;:29;;;;;;;;;;;;;:24;;31455:23;31401:24;31455:14;:23::i;:::-;31446:46;;;;;;;;;;;;31326:174;;:::o;111305:303::-;111378:4;;111395:182;111416:21;;;111395:182;;;111541:10;111515:22;111523:9;;111533:2;111523:13;;;;;;;:::i;:::-;;;;;;;111515:7;:22::i;:::-;:36;;;111507:58;;;;-1:-1:-1;;;111507:58:0;;31251:2:1;111507:58:0;;;31233:21:1;31290:1;31270:18;;;31263:29;31328:11;31308:18;;;31301:39;31357:18;;111507:58:0;31049:332:1;111507:58:0;111439:4;;;;:::i;:::-;;;;111395:182;;106353:144;106419:16;;;;:6;:16;;;;;;;;106418:17;106410:45;;;;-1:-1:-1;;;106410:45:0;;31588:2:1;106410:45:0;;;31570:21:1;31627:2;31607:18;;;31600:30;31666:17;31646:18;;;31639:45;31701:18;;106410:45:0;31386:339:1;106410:45:0;106466:16;;;;:6;:16;;;;;:23;;;;106485:4;106466:23;;;106353:144::o;27638:348::-;27731:4;27433:16;;;:7;:16;;;;;;:30;:16;27748:73;;;;-1:-1:-1;;;27748:73:0;;31932:2:1;27748:73:0;;;31914:21:1;31971:2;31951:18;;;31944:30;32010:34;31990:18;;;31983:62;32081:14;32061:18;;;32054:42;32113:19;;27748:73:0;31730:408:1;27748:73:0;27832:13;27848:23;27863:7;27848:14;:23::i;:::-;27832:39;;27901:5;27890:16;;:7;:16;;;:51;;;;27934:7;27910:31;;:20;27922:7;27910:11;:20::i;:::-;:31;;;27890:51;:87;;;;27945:32;27962:5;27969:7;27945:16;:32::i;30630:578::-;30789:4;30762:31;;:23;30777:7;30762:14;:23::i;:::-;:31;;;30754:85;;;;-1:-1:-1;;;30754:85:0;;32345:2:1;30754:85:0;;;32327:21:1;32384:2;32364:18;;;32357:30;32423:34;32403:18;;;32396:62;32494:11;32474:18;;;32467:39;32523:19;;30754:85:0;32143:405:1;30754:85:0;30858:16;;;30850:65;;;;-1:-1:-1;;;30850:65:0;;32755:2:1;30850:65:0;;;32737:21:1;32794:2;32774:18;;;32767:30;32833:34;32813:18;;;32806:62;32904:6;32884:18;;;32877:34;32928:19;;30850:65:0;32553:400:1;30850:65:0;31032:29;31049:1;31053:7;31032:8;:29::i;:::-;31074:15;;;;;;;:9;:15;;;;;:20;;31093:1;;31074:15;:20;;31093:1;;31074:20;:::i;:::-;;;;-1:-1:-1;;31105:13:0;;;;;;;:9;:13;;;;;:18;;31122:1;;31105:13;:18;;31122:1;;31105:18;:::i;:::-;;;;-1:-1:-1;;31134:16:0;;;;:7;:16;;;;;;:21;;;;;;;;;;;;;;31173:27;;31134:16;;31173:27;;;;;;;30630:578;;;:::o;50913:98::-;50971:7;50998:5;51002:1;50998;:5;:::i;51312:98::-;51370:7;51397:5;51401:1;51397;:5;:::i;57469:132::-;57516:40;57526:3;57531:24;:14;37848;;37756:114;57531:24;57516:9;:40::i;:::-;57567:26;:14;37967:19;;37985:1;37967:19;;;37878:127;106563:146;106631:16;;;;:6;:16;;;;;;;;106630:17;106622:45;;;;-1:-1:-1;;;106622:45:0;;31588:2:1;106622:45:0;;;31570:21:1;31627:2;31607:18;;;31600:30;31666:17;31646:18;;;31639:45;31701:18;;106622:45:0;31386:339:1;106622:45:0;106678:16;;;;:6;:16;;;;;:23;;;;106697:4;106678:23;;;106563:146::o;36745:173::-;36801:16;36820:6;;;36837:17;;;;;;;;;;36870:40;;36820:6;;;;;;;36870:40;;36801:16;36870:40;36790:128;36745:173;:::o;105930:362::-;104765:2;106053:14;;106070:1;106053:18;;;;:::i;:::-;:36;106045:63;;;;-1:-1:-1;;;106045:63:0;;33474:2:1;106045:63:0;;;33456:21:1;33513:2;33493:18;;;33486:30;33552:16;33532:18;;;33525:44;33586:18;;106045:63:0;33272:338:1;106045:63:0;106144:14;;;;106187:1;;106119:22;106169:19;106187:1;106144:14;106169:19;:::i;:::-;;;;;;;;106199:53;106221:4;106228:3;106233:14;106199:53;;;;;;;;;;;;26716:315;26873:28;26883:4;26889:2;26893:7;26873:9;:28::i;:::-;26920:48;26943:4;26949:2;26953:7;26962:5;26920:22;:48::i;:::-;26912:111;;;;-1:-1:-1;;;26912:111:0;;33817:2:1;26912:111:0;;;33799:21:1;33856:2;33836:18;;;33829:30;33895:34;33875:18;;;33868:62;33966:20;33946:18;;;33939:48;34004:19;;26912:111:0;33615:414:1;16854:723:0;16910:13;17131:10;17127:53;;-1:-1:-1;;17158:10:0;;;;;;;;;;;;;;;;;;16854:723::o;17127:53::-;17205:5;17190:12;17246:78;17253:9;;17246:78;;17279:8;;;;:::i;:::-;;-1:-1:-1;17302:10:0;;-1:-1:-1;17310:2:0;17302:10;;:::i;:::-;;;17246:78;;;17334:19;17366:6;17356:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;17356:17:0;;17334:39;;17384:154;17391:10;;17384:154;;17418:11;17428:1;17418:11;;:::i;:::-;;-1:-1:-1;17487:10:0;17495:2;17487:5;:10;:::i;:::-;17474:24;;:2;:24;:::i;:::-;17461:39;;17444:6;17451;17444:14;;;;;;;;:::i;:::-;;;;:56;;;;;;;;;;-1:-1:-1;17515:11:0;17524:2;17515:11;;:::i;:::-;;;17384:154;;60848:291;60945:4;;61012:3;61017:5;16395:10;60995:42;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;60985:53;;60995:42;60985:53;;;;61119:12;;60985:53;;-1:-1:-1;61119:12:0;;61058:57;61104:10;61058:37;60985:53;46749:58;;35622:66:1;46749:58:0;;;35610:79:1;35705:12;;;35698:28;;;46616:7:0;;35742:12:1;;46749:58:0;;;;;;;;;;;;46739:69;;;;;;46732:76;;46547:269;;;;61058:37;:45;;:57::i;:::-;:73;;;;60848:291;-1:-1:-1;;;60848:291:0:o;28328:110::-;28404:26;28414:2;28418:7;28404:26;;;;;;;;;;;;:9;:26::i;32065:799::-;32220:4;32241:13;;;8668:20;8716:8;32237:620;;32277:72;;;;;:36;;;;;;:72;;16395:10;;32328:4;;32334:7;;32343:5;;32277:72;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;32277:72:0;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;32273:529;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;32519:13:0;;32515:272;;32562:60;;-1:-1:-1;;;32562:60:0;;33817:2:1;32562:60:0;;;33799:21:1;33856:2;33836:18;;;33829:30;33895:34;33875:18;;;33868:62;33966:20;33946:18;;;33939:48;34004:19;;32562:60:0;33615:414:1;32515:272:0;32737:6;32731:13;32722:6;32718:2;32714:15;32707:38;32273:529;32400:51;;32410:41;32400:51;;-1:-1:-1;32393:58:0;;32237:620;-1:-1:-1;32841:4:0;32834:11;;42698:231;42776:7;42797:17;42816:18;42838:27;42849:4;42855:9;42838:10;:27::i;:::-;42796:69;;;;42876:18;42888:5;42876:11;:18::i;:::-;-1:-1:-1;42912:9:0;42698:231;-1:-1:-1;;;42698:231:0:o;28665:321::-;28795:18;28801:2;28805:7;28795:5;:18::i;:::-;28846:54;28877:1;28881:2;28885:7;28894:5;28846:22;:54::i;:::-;28824:154;;;;-1:-1:-1;;;28824:154:0;;33817:2:1;28824:154:0;;;33799:21:1;33856:2;33836:18;;;33829:30;33895:34;33875:18;;;33868:62;33966:20;33946:18;;;33939:48;34004:19;;28824:154:0;33615:414:1;40588:1308:0;40669:7;40678:12;40903:9;:16;40923:2;40903:22;40899:990;;;41199:4;41184:20;;41178:27;41249:4;41234:20;;41228:27;41307:4;41292:20;;41286:27;40942:9;41278:36;41350:25;41361:4;41278:36;41178:27;41228;41350:10;:25::i;:::-;41343:32;;;;;;;;;40899:990;41397:9;:16;41417:2;41397:22;41393:496;;;41672:4;41657:20;;41651:27;41723:4;41708:20;;41702:27;41765:23;41776:4;41651:27;41702;41765:10;:23::i;:::-;41758:30;;;;;;;;41393:496;-1:-1:-1;41837:1:0;;-1:-1:-1;41841:35:0;41821:56;;38859:643;38937:20;38928:5;:29;;;;;;;;:::i;:::-;;38924:571;;;38859:643;:::o;38924:571::-;39035:29;39026:5;:38;;;;;;;;:::i;:::-;;39022:473;;;39081:34;;-1:-1:-1;;;39081:34:0;;36156:2:1;39081:34:0;;;36138:21:1;36195:2;36175:18;;;36168:30;36234:26;36214:18;;;36207:54;36278:18;;39081:34:0;35954:348:1;39022:473:0;39146:35;39137:5;:44;;;;;;;;:::i;:::-;;39133:362;;;39198:41;;-1:-1:-1;;;39198:41:0;;36509:2:1;39198:41:0;;;36491:21:1;36548:2;36528:18;;;36521:30;36587:33;36567:18;;;36560:61;36638:18;;39198:41:0;36307:355:1;39133:362:0;39270:30;39261:5;:39;;;;;;;;:::i;:::-;;39257:238;;;39317:44;;-1:-1:-1;;;39317:44:0;;36869:2:1;39317:44:0;;;36851:21:1;36908:2;36888:18;;;36881:30;36947:34;36927:18;;;36920:62;37018:4;36998:18;;;36991:32;37040:19;;39317:44:0;36667:398:1;39257:238:0;39392:30;39383:5;:39;;;;;;;;:::i;:::-;;39379:116;;;39439:44;;-1:-1:-1;;;39439:44:0;;37272:2:1;39439:44:0;;;37254:21:1;37311:2;37291:18;;;37284:30;37350:34;37330:18;;;37323:62;37421:4;37401:18;;;37394:32;37443:19;;39439:44:0;37070:398:1;29322:382:0;29402:16;;;29394:61;;;;-1:-1:-1;;;29394:61:0;;37675:2:1;29394:61:0;;;37657:21:1;;;37694:18;;;37687:30;37753:34;37733:18;;;37726:62;37805:18;;29394:61:0;37473:356:1;29394:61:0;27409:4;27433:16;;;:7;:16;;;;;;:30;:16;:30;29466:58;;;;-1:-1:-1;;;29466:58:0;;38036:2:1;29466:58:0;;;38018:21:1;38075:2;38055:18;;;38048:30;38114;38094:18;;;38087:58;38162:18;;29466:58:0;37834:352:1;29466:58:0;29595:13;;;;;;;:9;:13;;;;;:18;;29612:1;;29595:13;:18;;29612:1;;29595:18;:::i;:::-;;;;-1:-1:-1;;29624:16:0;;;;:7;:16;;;;;;:21;;;;;;;;;;;;;29663:33;;29624:16;;;29663:33;;29624:16;;29663:33;29322:382;;:::o;44197:1632::-;44328:7;;45262:66;45249:79;;45245:163;;;-1:-1:-1;45361:1:0;;-1:-1:-1;45365:30:0;45345:51;;45245:163;45422:1;:7;;45427:2;45422:7;;:18;;;;;45433:1;:7;;45438:2;45433:7;;45422:18;45418:102;;;-1:-1:-1;45473:1:0;;-1:-1:-1;45477:30:0;45457:51;;45418:102;45634:24;;;45617:14;45634:24;;;;;;;;;38418:25:1;;;38491:4;38479:17;;38459:18;;;38452:45;;;;38513:18;;;38506:34;;;38556:18;;;38549:34;;;45634:24:0;;38390:19:1;;45634:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;45634:24:0;;;;;;-1:-1:-1;;45673:20:0;;;45669:103;;45726:1;45730:29;45710:50;;;;;;;45669:103;45792:6;-1:-1:-1;45800:20:0;;-1:-1:-1;44197:1632:0;;;;;;;;:::o;43192:391::-;43306:7;;43415:66;43407:75;;43509:3;43505:12;;;43519:2;43501:21;43550:25;43561:4;43501:21;43570:1;43407:75;43550:10;:25::i;:::-;43543:32;;;;;;43192:391;;;;;;:::o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;196:177:1;281:66;274:5;270:78;263:5;260:89;250:117;;363:1;360;353:12;378:245;436:6;489:2;477:9;468:7;464:23;460:32;457:52;;;505:1;502;495:12;457:52;544:9;531:23;563:30;587:5;563:30;:::i;820:258::-;892:1;902:113;916:6;913:1;910:13;902:113;;;992:11;;;986:18;973:11;;;966:39;938:2;931:10;902:113;;;1033:6;1030:1;1027:13;1024:48;;;-1:-1:-1;;1068:1:1;1050:16;;1043:27;820:258::o;1083:317::-;1125:3;1163:5;1157:12;1190:6;1185:3;1178:19;1206:63;1262:6;1255:4;1250:3;1246:14;1239:4;1232:5;1228:16;1206:63;:::i;:::-;1314:2;1302:15;1319:66;1298:88;1289:98;;;;1389:4;1285:109;;1083:317;-1:-1:-1;;1083:317:1:o;1405:220::-;1554:2;1543:9;1536:21;1517:4;1574:45;1615:2;1604:9;1600:18;1592:6;1574:45;:::i;1630:118::-;1716:5;1709:13;1702:21;1695:5;1692:32;1682:60;;1738:1;1735;1728:12;1753:241;1809:6;1862:2;1850:9;1841:7;1837:23;1833:32;1830:52;;;1878:1;1875;1868:12;1830:52;1917:9;1904:23;1936:28;1958:5;1936:28;:::i;1999:180::-;2058:6;2111:2;2099:9;2090:7;2086:23;2082:32;2079:52;;;2127:1;2124;2117:12;2079:52;-1:-1:-1;2150:23:1;;1999:180;-1:-1:-1;1999:180:1:o;2415:154::-;2501:42;2494:5;2490:54;2483:5;2480:65;2470:93;;2559:1;2556;2549:12;2574:315;2642:6;2650;2703:2;2691:9;2682:7;2678:23;2674:32;2671:52;;;2719:1;2716;2709:12;2671:52;2758:9;2745:23;2777:31;2802:5;2777:31;:::i;:::-;2827:5;2879:2;2864:18;;;;2851:32;;-1:-1:-1;;;2574:315:1:o;2894:367::-;2957:8;2967:6;3021:3;3014:4;3006:6;3002:17;2998:27;2988:55;;3039:1;3036;3029:12;2988:55;-1:-1:-1;3062:20:1;;3105:18;3094:30;;3091:50;;;3137:1;3134;3127:12;3091:50;3174:4;3166:6;3162:17;3150:29;;3234:3;3227:4;3217:6;3214:1;3210:14;3202:6;3198:27;3194:38;3191:47;3188:67;;;3251:1;3248;3241:12;3266:437;3352:6;3360;3413:2;3401:9;3392:7;3388:23;3384:32;3381:52;;;3429:1;3426;3419:12;3381:52;3469:9;3456:23;3502:18;3494:6;3491:30;3488:50;;;3534:1;3531;3524:12;3488:50;3573:70;3635:7;3626:6;3615:9;3611:22;3573:70;:::i;:::-;3662:8;;3547:96;;-1:-1:-1;3266:437:1;-1:-1:-1;;;;3266:437:1:o;3708:184::-;3760:77;3757:1;3750:88;3857:4;3854:1;3847:15;3881:4;3878:1;3871:15;3897:690;3961:5;3991:18;4032:2;4024:6;4021:14;4018:40;;;4038:18;;:::i;:::-;4172:2;4166:9;4238:2;4226:15;;4077:66;4222:24;;;4248:2;4218:33;4214:42;4202:55;;;4272:18;;;4292:22;;;4269:46;4266:72;;;4318:18;;:::i;:::-;4358:10;4354:2;4347:22;4387:6;4378:15;;4417:6;4409;4402:22;4457:3;4448:6;4443:3;4439:16;4436:25;4433:45;;;4474:1;4471;4464:12;4433:45;4524:6;4519:3;4512:4;4504:6;4500:17;4487:44;4579:1;4572:4;4563:6;4555;4551:19;4547:30;4540:41;;;;3897:690;;;;;:::o;4592:220::-;4634:5;4687:3;4680:4;4672:6;4668:17;4664:27;4654:55;;4705:1;4702;4695:12;4654:55;4727:79;4802:3;4793:6;4780:20;4773:4;4765:6;4761:17;4727:79;:::i;4817:665::-;4912:6;4920;4928;4936;4989:3;4977:9;4968:7;4964:23;4960:33;4957:53;;;5006:1;5003;4996:12;4957:53;5045:9;5032:23;5064:31;5089:5;5064:31;:::i;:::-;5114:5;-1:-1:-1;5171:2:1;5156:18;;5143:32;5184:33;5143:32;5184:33;:::i;:::-;5236:7;-1:-1:-1;5290:2:1;5275:18;;5262:32;;-1:-1:-1;5345:2:1;5330:18;;5317:32;5372:18;5361:30;;5358:50;;;5404:1;5401;5394:12;5358:50;5427:49;5468:7;5459:6;5448:9;5444:22;5427:49;:::i;:::-;5417:59;;;4817:665;;;;;;;:::o;5740:247::-;5799:6;5852:2;5840:9;5831:7;5827:23;5823:32;5820:52;;;5868:1;5865;5858:12;5820:52;5907:9;5894:23;5926:31;5951:5;5926:31;:::i;5992:456::-;6069:6;6077;6085;6138:2;6126:9;6117:7;6113:23;6109:32;6106:52;;;6154:1;6151;6144:12;6106:52;6193:9;6180:23;6212:31;6237:5;6212:31;:::i;:::-;6262:5;-1:-1:-1;6319:2:1;6304:18;;6291:32;6332:33;6291:32;6332:33;:::i;:::-;5992:456;;6384:7;;-1:-1:-1;;;6438:2:1;6423:18;;;;6410:32;;5992:456::o;6453:248::-;6521:6;6529;6582:2;6570:9;6561:7;6557:23;6553:32;6550:52;;;6598:1;6595;6588:12;6550:52;-1:-1:-1;;6621:23:1;;;6691:2;6676:18;;;6663:32;;-1:-1:-1;6453:248:1:o;7008:773::-;7130:6;7138;7146;7154;7207:2;7195:9;7186:7;7182:23;7178:32;7175:52;;;7223:1;7220;7213:12;7175:52;7263:9;7250:23;7292:18;7333:2;7325:6;7322:14;7319:34;;;7349:1;7346;7339:12;7319:34;7388:70;7450:7;7441:6;7430:9;7426:22;7388:70;:::i;:::-;7477:8;;-1:-1:-1;7362:96:1;-1:-1:-1;7565:2:1;7550:18;;7537:32;;-1:-1:-1;7581:16:1;;;7578:36;;;7610:1;7607;7600:12;7578:36;;7649:72;7713:7;7702:8;7691:9;7687:24;7649:72;:::i;:::-;7008:773;;;;-1:-1:-1;7740:8:1;-1:-1:-1;;;;7008:773:1:o;8046:592::-;8117:6;8125;8178:2;8166:9;8157:7;8153:23;8149:32;8146:52;;;8194:1;8191;8184:12;8146:52;8234:9;8221:23;8263:18;8304:2;8296:6;8293:14;8290:34;;;8320:1;8317;8310:12;8290:34;8358:6;8347:9;8343:22;8333:32;;8403:7;8396:4;8392:2;8388:13;8384:27;8374:55;;8425:1;8422;8415:12;8374:55;8465:2;8452:16;8491:2;8483:6;8480:14;8477:34;;;8507:1;8504;8497:12;8477:34;8552:7;8547:2;8538:6;8534:2;8530:15;8526:24;8523:37;8520:57;;;8573:1;8570;8563:12;8520:57;8604:2;8596:11;;;;;8626:6;;-1:-1:-1;8046:592:1;;-1:-1:-1;;;;8046:592:1:o;8643:382::-;8708:6;8716;8769:2;8757:9;8748:7;8744:23;8740:32;8737:52;;;8785:1;8782;8775:12;8737:52;8824:9;8811:23;8843:31;8868:5;8843:31;:::i;:::-;8893:5;-1:-1:-1;8950:2:1;8935:18;;8922:32;8963:30;8922:32;8963:30;:::i;:::-;9012:7;9002:17;;;8643:382;;;;;:::o;9808:450::-;9877:6;9930:2;9918:9;9909:7;9905:23;9901:32;9898:52;;;9946:1;9943;9936:12;9898:52;9986:9;9973:23;10019:18;10011:6;10008:30;10005:50;;;10051:1;10048;10041:12;10005:50;10074:22;;10127:4;10119:13;;10115:27;-1:-1:-1;10105:55:1;;10156:1;10153;10146:12;10105:55;10179:73;10244:7;10239:2;10226:16;10221:2;10217;10213:11;10179:73;:::i;10263:388::-;10340:6;10348;10401:2;10389:9;10380:7;10376:23;10372:32;10369:52;;;10417:1;10414;10407:12;10369:52;10453:9;10440:23;10430:33;;10514:2;10503:9;10499:18;10486:32;10541:18;10533:6;10530:30;10527:50;;;10573:1;10570;10563:12;10527:50;10596:49;10637:7;10628:6;10617:9;10613:22;10596:49;:::i;:::-;10586:59;;;10263:388;;;;;:::o;10656:::-;10724:6;10732;10785:2;10773:9;10764:7;10760:23;10756:32;10753:52;;;10801:1;10798;10791:12;10753:52;10840:9;10827:23;10859:31;10884:5;10859:31;:::i;:::-;10909:5;-1:-1:-1;10966:2:1;10951:18;;10938:32;10979:33;10938:32;10979:33;:::i;11377:437::-;11456:1;11452:12;;;;11499;;;11520:61;;11574:4;11566:6;11562:17;11552:27;;11520:61;11627:2;11619:6;11616:14;11596:18;11593:38;11590:218;;;11664:77;11661:1;11654:88;11765:4;11762:1;11755:15;11793:4;11790:1;11783:15;11590:218;;11377:437;;;:::o;14405:184::-;14475:6;14528:2;14516:9;14507:7;14503:23;14499:32;14496:52;;;14544:1;14541;14534:12;14496:52;-1:-1:-1;14567:16:1;;14405:184;-1:-1:-1;14405:184:1:o;15310:::-;15362:77;15359:1;15352:88;15459:4;15456:1;15449:15;15483:4;15480:1;15473:15;15499:184;15551:77;15548:1;15541:88;15648:4;15645:1;15638:15;15672:4;15669:1;15662:15;15688:195;15727:3;15758:66;15751:5;15748:77;15745:103;;;15828:18;;:::i;:::-;-1:-1:-1;15875:1:1;15864:13;;15688:195::o;19403:228::-;19443:7;19569:1;19501:66;19497:74;19494:1;19491:81;19486:1;19479:9;19472:17;19468:105;19465:131;;;19576:18;;:::i;:::-;-1:-1:-1;19616:9:1;;19403:228::o;19636:128::-;19676:3;19707:1;19703:6;19700:1;19697:13;19694:39;;;19713:18;;:::i;:::-;-1:-1:-1;19749:9:1;;19636:128::o;20150:125::-;20190:4;20218:1;20215;20212:8;20209:34;;;20223:18;;:::i;:::-;-1:-1:-1;20260:9:1;;20150:125::o;21747:245::-;21814:6;21867:2;21855:9;21846:7;21842:23;21838:32;21835:52;;;21883:1;21880;21873:12;21835:52;21915:9;21909:16;21934:28;21956:5;21934:28;:::i;24903:1088::-;24988:12;;24953:3;;25043:1;25063:18;;;;25116;;;;25143:61;;25197:4;25189:6;25185:17;25175:27;;25143:61;25223:2;25271;25263:6;25260:14;25240:18;25237:38;25234:218;;;25308:77;25305:1;25298:88;25409:4;25406:1;25399:15;25437:4;25434:1;25427:15;25234:218;25468:18;25495:162;;;;25671:1;25666:319;;;;25461:524;;25495:162;25543:66;25532:9;25528:82;25523:3;25516:95;25640:6;25635:3;25631:16;25624:23;;25495:162;;25666:319;24850:1;24843:14;;;24887:4;24874:18;;25760:1;25774:165;25788:6;25785:1;25782:13;25774:165;;;25866:14;;25853:11;;;25846:35;25909:16;;;;25803:10;;25774:165;;;25778:3;;25968:6;25963:3;25959:16;25952:23;;25461:524;;;;;;;24903:1088;;;;:::o;25996:958::-;26316:3;26344:38;26378:3;26370:6;26344:38;:::i;:::-;26411:6;26405:13;26427:52;26472:6;26468:2;26461:4;26453:6;26449:17;26427:52;:::i;:::-;26541:13;;26501:15;;;26563:57;26541:13;26501:15;26597:4;26585:17;;26563:57;:::i;:::-;26687:13;;26642:20;;;26709:57;26687:13;26642:20;26743:4;26731:17;;26709:57;:::i;:::-;26833:13;;26788:20;;;26855:57;26833:13;26788:20;26889:4;26877:17;;26855:57;:::i;:::-;26928:20;;25996:958;-1:-1:-1;;;;;;;25996:958:1:o;29338:280::-;29437:6;29490:2;29478:9;29469:7;29465:23;29461:32;29458:52;;;29506:1;29503;29496:12;29458:52;29538:9;29532:16;29557:31;29582:5;29557:31;:::i;32958:184::-;33010:77;33007:1;33000:88;33107:4;33104:1;33097:15;33131:4;33128:1;33121:15;33147:120;33187:1;33213;33203:35;;33218:18;;:::i;:::-;-1:-1:-1;33252:9:1;;33147:120::o;34034:112::-;34066:1;34092;34082:35;;34097:18;;:::i;:::-;-1:-1:-1;34131:9:1;;34034:112::o;34151:453::-;34352:3;34383:73;34417:38;34451:3;34443:6;34417:38;:::i;:::-;34409:6;34383:73;:::i;:::-;34487:2;34483:15;;;;34500:66;34479:88;34465:103;;-1:-1:-1;;34595:2:1;34584:14;;34151:453;-1:-1:-1;;34151:453:1:o;34609:512::-;34803:4;34832:42;34913:2;34905:6;34901:15;34890:9;34883:34;34965:2;34957:6;34953:15;34948:2;34937:9;34933:18;34926:43;;35005:6;35000:2;34989:9;34985:18;34978:34;35048:3;35043:2;35032:9;35028:18;35021:31;35069:46;35110:3;35099:9;35095:19;35087:6;35069:46;:::i;:::-;35061:54;34609:512;-1:-1:-1;;;;;;34609:512:1:o;35126:249::-;35195:6;35248:2;35236:9;35227:7;35223:23;35219:32;35216:52;;;35264:1;35261;35254:12;35216:52;35296:9;35290:16;35315:30;35339:5;35315:30;:::i;35765:184::-;35817:77;35814:1;35807:88;35914:4;35911:1;35904:15;35938:4;35935:1;35928:15

Swarm Source

ipfs://aced6b5fac40f572f2cbeefbbfa8e32bedbe94eb87324054954035292f3691c3
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.