ETH Price: $2,603.54 (-1.66%)

Token

PENGU (PENGU)
 

Overview

Max Total Supply

337 PENGU

Holders

110

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

Balance
1 PENGU
0xf246f2d7b74b062184c94a4da721c86d55b2048e
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:
PENGU

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2024-03-04
*/

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// +++++++++++++++++++++++************+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++#@@@@@@@@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*++++++++++++++++++++++
// ++++++++++++++++++++++#@@@@@@@@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*++++++++++++++++++++++
// ++++++++++++++++++++++#@@@@@@@@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*++++++++++++++++++++++
// ++++++++++++++++%%%%%%@@@@@@@%%%%%%%%%+............=%%%%%#......+%%#######++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%*+++++-            =%%%%%#      =+++++*%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:                  =%%%%%#            :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:                  =%%%%%#            :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:               ...=######            :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:               +##+---------.        :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:               +##+---------.        :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:               +##+---------.        :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:        .###   +##+---------.  +##=  :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:        .***   =++=:::::::::   =**=  :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:                                     :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:                                     :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:                                     :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%:                                     :%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%=-------------------------------------=%%#++++++++++++++++
// ++++++++++++++++%@@@@@@@@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#++++++++++++++++
// ++++++++++++++++*********************************************************+++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

/**
 * @dev Interface of ERC721A.
 */
interface IERC721A {
    /**
     * The caller must own the token or be an approved operator.
     */
    error ApprovalCallerNotOwnerNorApproved();

    /**
     * The token does not exist.
     */
    error ApprovalQueryForNonexistentToken();

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

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

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

    /**
     * The token does not exist.
     */
    error OwnerQueryForNonexistentToken();

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

    /**
     * The token must be owned by `from`.
     */
    error TransferFromIncorrectOwner();

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

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

    /**
     * The token does not exist.
     */
    error URIQueryForNonexistentToken();

    /**
     * The `quantity` minted with ERC2309 exceeds the safety limit.
     */
    error MintERC2309QuantityExceedsLimit();

    /**
     * The `extraData` cannot be set on an unintialized ownership slot.
     */
    error OwnershipNotInitializedForExtraData();

    // =============================================================
    //                            STRUCTS
    // =============================================================

    struct TokenOwnership {
        // The address of the owner.
        address addr;
        // Stores the start time of ownership with minimal overhead for tokenomics.
        uint64 startTimestamp;
        // Whether the token has been burned.
        bool burned;
        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
        uint24 extraData;
    }

    // =============================================================
    //                         TOKEN COUNTERS
    // =============================================================

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() external view returns (uint256);

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    // =============================================================
    //                            IERC721
    // =============================================================

    /**
     * @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,
        bytes calldata data
    ) external payable;

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable;

    /**
     * @dev Transfers `tokenId` 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 payable;

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

    /**
     * @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 the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

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

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

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

    // =============================================================
    //                           IERC2309
    // =============================================================

    /**
     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
     * (inclusive) is transferred from `from` to `to`, as defined in the
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
     *
     * See {_mintERC2309} for more details.
     */
    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}

/**
 * @dev Interface of ERC721 token receiver.
 */
interface ERC721A__IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

/**
 * @title ERC721A
 *
 * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
 * Non-Fungible Token Standard, including the Metadata extension.
 * Optimized for lower gas during batch mints.
 *
 * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
 * starting from `_startTokenId()`.
 *
 * Assumptions:
 *
 * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
 * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
 */
contract ERC721A is IERC721A {
    // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
    struct TokenApprovalRef {
        address value;
    }

    // =============================================================
    //                           CONSTANTS
    // =============================================================

    // Mask of an entry in packed address data.
    uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;

    // The bit position of `numberMinted` in packed address data.
    uint256 private constant _BITPOS_NUMBER_MINTED = 64;

    // The bit position of `numberBurned` in packed address data.
    uint256 private constant _BITPOS_NUMBER_BURNED = 128;

    // The bit position of `aux` in packed address data.
    uint256 private constant _BITPOS_AUX = 192;

    // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
    uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;

    // The bit position of `startTimestamp` in packed ownership.
    uint256 private constant _BITPOS_START_TIMESTAMP = 160;

    // The bit mask of the `burned` bit in packed ownership.
    uint256 private constant _BITMASK_BURNED = 1 << 224;

    // The bit position of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;

    // The bit mask of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;

    // The bit position of `extraData` in packed ownership.
    uint256 private constant _BITPOS_EXTRA_DATA = 232;

    // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
    uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;

    // The mask of the lower 160 bits for addresses.
    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;

    // The maximum `quantity` that can be minted with {_mintERC2309}.
    // This limit is to prevent overflows on the address data entries.
    // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
    // is required to cause an overflow, which is unrealistic.
    uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;

    // The `Transfer` event signature is given by:
    // `keccak256(bytes("Transfer(address,address,uint256)"))`.
    bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    // =============================================================
    //                            STORAGE
    // =============================================================

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

    // The number of tokens burned.
    uint256 private _burnCounter;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to ownership details
    // An empty struct value does not necessarily mean the token is unowned.
    // See {_packedOwnershipOf} implementation for details.
    //
    // Bits Layout:
    // - [0..159]   `addr`
    // - [160..223] `startTimestamp`
    // - [224]      `burned`
    // - [225]      `nextInitialized`
    // - [232..255] `extraData`
    mapping(uint256 => uint256) private _packedOwnerships;

    // Mapping owner address to address data.
    //
    // Bits Layout:
    // - [0..63]    `balance`
    // - [64..127]  `numberMinted`
    // - [128..191] `numberBurned`
    // - [192..255] `aux`
    mapping(address => uint256) private _packedAddressData;

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

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

    // =============================================================
    //                          CONSTRUCTOR
    // =============================================================

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _currentIndex = _startTokenId();
    }

    // =============================================================
    //                   TOKEN COUNTING OPERATIONS
    // =============================================================

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

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

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        // Counter underflow is impossible as _burnCounter cannot be incremented
        // more than `_currentIndex - _startTokenId()` times.
        unchecked {
            return _currentIndex - _burnCounter - _startTokenId();
        }
    }

    /**
     * @dev Returns the total amount of tokens minted in the contract.
     */
    function _totalMinted() internal view virtual returns (uint256) {
        // Counter underflow is impossible as `_currentIndex` does not decrement,
        // and it is initialized to `_startTokenId()`.
        unchecked {
            return _currentIndex - _startTokenId();
        }
    }

    /**
     * @dev Returns the total number of tokens burned.
     */
    function _totalBurned() internal view virtual returns (uint256) {
        return _burnCounter;
    }

    // =============================================================
    //                    ADDRESS DATA OPERATIONS
    // =============================================================

    /**
     * @dev Returns the number of tokens in `owner`'s account.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        if (owner == address(0)) revert BalanceQueryForZeroAddress();
        return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens minted by `owner`.
     */
    function _numberMinted(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens burned by or on behalf of `owner`.
     */
    function _numberBurned(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     */
    function _getAux(address owner) internal view returns (uint64) {
        return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
    }

    /**
     * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     * If there are multiple variables, please pack them into a uint64.
     */
    function _setAux(address owner, uint64 aux) internal virtual {
        uint256 packed = _packedAddressData[owner];
        uint256 auxCasted;
        // Cast `aux` with assembly to avoid redundant masking.
        assembly {
            auxCasted := aux
        }
        packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
        _packedAddressData[owner] = packed;
    }

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        // The interface IDs are constants representing the first 4 bytes
        // of the XOR of all function selectors in the interface.
        // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
        // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
        return
            interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
            interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
            interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
    }

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

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

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        if (!_exists(tokenId)) revert URIQueryForNonexistentToken();

        string memory baseURI = _baseURI();
        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
    }

    /**
     * @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, it can be overridden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return '';
    }

    // =============================================================
    //                     OWNERSHIPS OPERATIONS
    // =============================================================

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        return address(uint160(_packedOwnershipOf(tokenId)));
    }

    /**
     * @dev Gas spent here starts off proportional to the maximum mint batch size.
     * It gradually moves to O(1) as tokens get transferred around over time.
     */
    function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnershipOf(tokenId));
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct at `index`.
     */
    function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnerships[index]);
    }

    /**
     * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
     */
    function _initializeOwnershipAt(uint256 index) internal virtual {
        if (_packedOwnerships[index] == 0) {
            _packedOwnerships[index] = _packedOwnershipOf(index);
        }
    }

    /**
     * Returns the packed ownership data of `tokenId`.
     */
    function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
        uint256 curr = tokenId;

        unchecked {
            if (_startTokenId() <= curr)
                if (curr < _currentIndex) {
                    uint256 packed = _packedOwnerships[curr];
                    // If not burned.
                    if (packed & _BITMASK_BURNED == 0) {
                        // Invariant:
                        // There will always be an initialized ownership slot
                        // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                        // before an unintialized ownership slot
                        // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                        // Hence, `curr` will not underflow.
                        //
                        // We can directly compare the packed value.
                        // If the address is zero, packed will be zero.
                        while (packed == 0) {
                            packed = _packedOwnerships[--curr];
                        }
                        return packed;
                    }
                }
        }
        revert OwnerQueryForNonexistentToken();
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
     */
    function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
        ownership.addr = address(uint160(packed));
        ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
        ownership.burned = packed & _BITMASK_BURNED != 0;
        ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
    }

    /**
     * @dev Packs ownership data into a single uint256.
     */
    function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
            result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
        }
    }

    /**
     * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
     */
    function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
        // For branchless setting of the `nextInitialized` flag.
        assembly {
            // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
            result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
        }
    }

    // =============================================================
    //                      APPROVAL OPERATIONS
    // =============================================================

    /**
     * @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) public payable virtual override {
        address owner = ownerOf(tokenId);

        if (_msgSenderERC721A() != owner)
            if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                revert ApprovalCallerNotOwnerNorApproved();
            }

        _tokenApprovals[tokenId].value = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();

        return _tokenApprovals[tokenId].value;
    }

    /**
     * @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) public virtual override {
        _operatorApprovals[_msgSenderERC721A()][operator] = approved;
        emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
    }

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

    /**
     * @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. See {_mint}.
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return
            _startTokenId() <= tokenId &&
            tokenId < _currentIndex && // If within bounds,
            _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
    }

    /**
     * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
     */
    function _isSenderApprovedOrOwner(
        address approvedAddress,
        address owner,
        address msgSender
    ) private pure returns (bool result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
            msgSender := and(msgSender, _BITMASK_ADDRESS)
            // `msgSender == owner || msgSender == approvedAddress`.
            result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
        }
    }

    /**
     * @dev Returns the storage slot and value for the approved address of `tokenId`.
     */
    function _getApprovedSlotAndAddress(uint256 tokenId)
        private
        view
        returns (uint256 approvedAddressSlot, address approvedAddress)
    {
        TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
        // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
        assembly {
            approvedAddressSlot := tokenApproval.slot
            approvedAddress := sload(approvedAddressSlot)
        }
    }

    // =============================================================
    //                      TRANSFER OPERATIONS
    // =============================================================

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * 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
    ) public payable virtual override {
        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);

        if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        // The nested ifs save around 20+ gas over a compound boolean condition.
        if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
            if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();

        if (to == address(0)) revert TransferToZeroAddress();

        _beforeTokenTransfers(from, to, tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // We can directly increment and decrement the balances.
            --_packedAddressData[from]; // Updates: `balance -= 1`.
            ++_packedAddressData[to]; // Updates: `balance += 1`.

            // Updates:
            // - `address` to the next owner.
            // - `startTimestamp` to the timestamp of transfering.
            // - `burned` to `false`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                to,
                _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, to, tokenId);
        _afterTokenTransfers(from, to, tokenId, 1);
    }

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public payable virtual override {
        safeTransferFrom(from, to, tokenId, '');
    }

    /**
     * @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 memory _data
    ) public payable virtual override {
        transferFrom(from, to, tokenId);
        if (to.code.length != 0)
            if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                revert TransferToNonERC721ReceiverImplementer();
            }
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token IDs
     * are about to be transferred. This includes minting.
     * And also called before burning one token.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * 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, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Hook that is called after a set of serially-ordered token IDs
     * have been transferred. This includes minting.
     * And also called after one token has been burned.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
     * transferred to `to`.
     * - When `from` is zero, `tokenId` has been minted for `to`.
     * - When `to` is zero, `tokenId` has been burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
     *
     * `from` - Previous owner of the given token ID.
     * `to` - Target address that will receive the token.
     * `tokenId` - Token ID to be transferred.
     * `_data` - Optional data to send along with the call.
     *
     * Returns whether the call correctly returned the expected magic value.
     */
    function _checkContractOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
            bytes4 retval
        ) {
            return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
        } catch (bytes memory reason) {
            if (reason.length == 0) {
                revert TransferToNonERC721ReceiverImplementer();
            } else {
                assembly {
                    revert(add(32, reason), mload(reason))
                }
            }
        }
    }

    // =============================================================
    //                        MINT OPERATIONS
    // =============================================================

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _mint(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (quantity == 0) revert MintZeroQuantity();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are incredibly unrealistic.
        // `balance` and `numberMinted` have a maximum limit of 2**64.
        // `tokenId` has a maximum limit of 2**256.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            uint256 toMasked;
            uint256 end = startTokenId + quantity;

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

                // The `iszero(eq(,))` check ensures that large values of `quantity`
                // that overflows uint256 will make the loop run out of gas.
                // The compiler will optimize the `iszero` away for performance.
                for {
                    let tokenId := add(startTokenId, 1)
                } iszero(eq(tokenId, end)) {
                    tokenId := add(tokenId, 1)
                } {
                    // Emit the `Transfer` event. Similar to above.
                    log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                }
            }
            if (toMasked == 0) revert MintToZeroAddress();

            _currentIndex = end;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * This function is intended for efficient minting only during contract creation.
     *
     * It emits only one {ConsecutiveTransfer} as defined in
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
     * instead of a sequence of {Transfer} event(s).
     *
     * Calling this function outside of contract creation WILL make your contract
     * non-compliant with the ERC721 standard.
     * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
     * {ConsecutiveTransfer} event is only permissible during contract creation.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {ConsecutiveTransfer} event.
     */
    function _mintERC2309(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (to == address(0)) revert MintToZeroAddress();
        if (quantity == 0) revert MintZeroQuantity();
        if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);

            _currentIndex = startTokenId + quantity;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Safely mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement
     * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
     * - `quantity` must be greater than 0.
     *
     * See {_mint}.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual {
        _mint(to, quantity);

        unchecked {
            if (to.code.length != 0) {
                uint256 end = _currentIndex;
                uint256 index = end - quantity;
                do {
                    if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
                } while (index < end);
                // Reentrancy protection.
                if (_currentIndex != end) revert();
            }
        }
    }

    /**
     * @dev Equivalent to `_safeMint(to, quantity, '')`.
     */
    function _safeMint(address to, uint256 quantity) internal virtual {
        _safeMint(to, quantity, '');
    }

    // =============================================================
    //                        BURN OPERATIONS
    // =============================================================

    /**
     * @dev Equivalent to `_burn(tokenId, false)`.
     */
    function _burn(uint256 tokenId) internal virtual {
        _burn(tokenId, false);
    }

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

        address from = address(uint160(prevOwnershipPacked));

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        if (approvalCheck) {
            // The nested ifs save around 20+ gas over a compound boolean condition.
            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
        }

        _beforeTokenTransfers(from, address(0), tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // Updates:
            // - `balance -= 1`.
            // - `numberBurned += 1`.
            //
            // We can directly decrement the balance, and increment the number burned.
            // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
            _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;

            // Updates:
            // - `address` to the last owner.
            // - `startTimestamp` to the timestamp of burning.
            // - `burned` to `true`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                from,
                (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, address(0), tokenId);
        _afterTokenTransfers(from, address(0), tokenId, 1);

        // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
        unchecked {
            _burnCounter++;
        }
    }

    // =============================================================
    //                     EXTRA DATA OPERATIONS
    // =============================================================

    /**
     * @dev Directly sets the extra data for the ownership data `index`.
     */
    function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
        uint256 packed = _packedOwnerships[index];
        if (packed == 0) revert OwnershipNotInitializedForExtraData();
        uint256 extraDataCasted;
        // Cast `extraData` with assembly to avoid redundant masking.
        assembly {
            extraDataCasted := extraData
        }
        packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
        _packedOwnerships[index] = packed;
    }

    /**
     * @dev Called during each token transfer to set the 24bit `extraData` field.
     * Intended to be overridden by the cosumer contract.
     *
     * `previousExtraData` - the value of `extraData` before transfer.
     *
     * 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, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _extraData(
        address from,
        address to,
        uint24 previousExtraData
    ) internal view virtual returns (uint24) {}

    /**
     * @dev Returns the next extra data for the packed ownership data.
     * The returned result is shifted into position.
     */
    function _nextExtraData(
        address from,
        address to,
        uint256 prevOwnershipPacked
    ) private view returns (uint256) {
        uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
        return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
    }

    // =============================================================
    //                       OTHER OPERATIONS
    // =============================================================

    /**
     * @dev Returns the message sender (defaults to `msg.sender`).
     *
     * If you are writing GSN compatible contracts, you need to override this function.
     */
    function _msgSenderERC721A() internal view virtual returns (address) {
        return msg.sender;
    }

    /**
     * @dev Converts a uint256 to its ASCII string decimal representation.
     */
    function _toString(uint256 value) internal pure virtual returns (string memory str) {
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
            let m := add(mload(0x40), 0xa0)
            // Update the free memory pointer to allocate.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                str := sub(str, 1)
                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))
                // Keep dividing `temp` until zero.
                temp := div(temp, 10)
                // prettier-ignore
                if iszero(temp) { break }
            }

            let length := sub(end, str)
            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 0x20)
            // Store the length.
            mstore(str, length)
        }
    }
}

// OpenZeppelin Contracts (last updated v5.0.0) (token/common/ERC2981.sol)

// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2981.sol)

// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

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

/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(
        uint256 tokenId,
        uint256 salePrice
    ) external view returns (address receiver, uint256 royaltyAmount);
}

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

/**
 * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
 *
 * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
 * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
 *
 * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
 * fee is specified in basis points by default.
 *
 * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
 * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
 * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
 */
abstract contract ERC2981 is IERC2981, ERC165 {
    struct RoyaltyInfo {
        address receiver;
        uint96 royaltyFraction;
    }

    RoyaltyInfo private _defaultRoyaltyInfo;
    mapping(uint256 tokenId => RoyaltyInfo) private _tokenRoyaltyInfo;

    /**
     * @dev The default royalty set is invalid (eg. (numerator / denominator) >= 1).
     */
    error ERC2981InvalidDefaultRoyalty(uint256 numerator, uint256 denominator);

    /**
     * @dev The default royalty receiver is invalid.
     */
    error ERC2981InvalidDefaultRoyaltyReceiver(address receiver);

    /**
     * @dev The royalty set for an specific `tokenId` is invalid (eg. (numerator / denominator) >= 1).
     */
    error ERC2981InvalidTokenRoyalty(uint256 tokenId, uint256 numerator, uint256 denominator);

    /**
     * @dev The royalty receiver for `tokenId` is invalid.
     */
    error ERC2981InvalidTokenRoyaltyReceiver(uint256 tokenId, address receiver);

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

    /**
     * @inheritdoc IERC2981
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address, uint256) {
        RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId];

        if (royalty.receiver == address(0)) {
            royalty = _defaultRoyaltyInfo;
        }

        uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator();

        return (royalty.receiver, royaltyAmount);
    }

    /**
     * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
     * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
     * override.
     */
    function _feeDenominator() internal pure virtual returns (uint96) {
        return 10000;
    }

    /**
     * @dev Sets the royalty information that all ids in this contract will default to.
     *
     * Requirements:
     *
     * - `receiver` cannot be the zero address.
     * - `feeNumerator` cannot be greater than the fee denominator.
     */
    function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
        uint256 denominator = _feeDenominator();
        if (feeNumerator > denominator) {
            // Royalty fee will exceed the sale price
            revert ERC2981InvalidDefaultRoyalty(feeNumerator, denominator);
        }
        if (receiver == address(0)) {
            revert ERC2981InvalidDefaultRoyaltyReceiver(address(0));
        }

        _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
    }

    /**
     * @dev Removes default royalty information.
     */
    function _deleteDefaultRoyalty() internal virtual {
        delete _defaultRoyaltyInfo;
    }

    /**
     * @dev Sets the royalty information for a specific token id, overriding the global default.
     *
     * Requirements:
     *
     * - `receiver` cannot be the zero address.
     * - `feeNumerator` cannot be greater than the fee denominator.
     */
    function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual {
        uint256 denominator = _feeDenominator();
        if (feeNumerator > denominator) {
            // Royalty fee will exceed the sale price
            revert ERC2981InvalidTokenRoyalty(tokenId, feeNumerator, denominator);
        }
        if (receiver == address(0)) {
            revert ERC2981InvalidTokenRoyaltyReceiver(tokenId, address(0));
        }

        _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
    }

    /**
     * @dev Resets royalty information for the token id back to the global default.
     */
    function _resetTokenRoyalty(uint256 tokenId) internal virtual {
        delete _tokenRoyaltyInfo[tokenId];
    }
}

// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

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

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

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

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

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

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

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

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

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

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

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

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

// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the Merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates Merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     *@dev The multiproof provided is not valid.
     */
    error MerkleProofInvalidMultiproof();

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     */
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Sorts the pair (a, b) and hashes the result.
     */
    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    /**
     * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
     */
    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

contract PENGU is ERC721A, Ownable, ERC2981 {
    error PENGU_MINT_PAUSED();
    error PENGU_WL_OG_MINT_NOT_ACTIVE();
    error PENGU_PUBLIC_MINT_NOT_ACTIVE();
    error PENGU_ZERO_ADDRESS();
    error PENGU_ZERO_PRICE();
    error PENGU_BLANK_URI();
    error PENGU_NOT_VERIFIED();
    error PENGU_INVALID_MERKLE_ROOT();
    error PENGU_NO_FUNDS_TO_WITHDRAW();
    error PENGU_WITHDRAWAL_FAILED();
    error PENGU_NONEXISTENT_TOKEN();
    error PENGU_INSUFFICIENT_FUNDS();
    error PENGU_NOT_A_TOKEN_OWNER();
    error PENGU_FREE_MINT_ALREADY_CLAIMED();
    error PENGU_WL_MINT_ALREADY_CLAIMED();
    error PENGU_FREE_CLAIM_LIMIT_REACHED();
    error PENGU_WL_CLAIM_LIMIT_REACHED();
    error PENGU_MINT_TRANSACTION_LIMIT_REACHED();

    enum SaleConfig {
        PAUSED,
        WL,
        MINT
    }

    enum MetaType {
        TYPE1,
        TYPE2
    }

    using Strings for uint256;

    ///////////////////////////////////////////////////////////
    //              Variables
    // ///////////////////////////////////////////////////////
    uint256 private nonce = 0;

    // SUPPLY AND RESERVE
    uint256 private constant SUPPLY = 7777;
    uint256 private constant ADMIN_RESERVE = 150;
    uint256 private constant FREE_MINT_RESERVE = 150;
    uint256 private constant WL_MINT_RESERVE = 1000;

    // METADATA URIs
    string private constant baseExtension = ".json";
    string private metadataBaseURI;
    string private metadataTwoBaseURI;
    string private unRevealedURI;

    // PRICES
    uint256 private mint_price = 0.02 ether;
    uint256 private wl_mint_price = 0.0175 ether;
    uint256 private mint_price_discounted = 0.0175 ether;
    uint256 private wl_mint_price_discounted = 0.015 ether;

    // LIMIT
    uint8 private claim_limit = 1;
    uint8 private wl_claim_limit = 2;
    uint8 private tx_limit = 10;
    uint8 private numberOfFreeMint = 0;
    uint8 private numberOfWlMint = 0;

    // OTHERS
    SaleConfig private saleConfig = SaleConfig.PAUSED;
    bool private revealed = false;
    bytes32 private merkleRoot;
    bytes32 private wl_merkleRoot;

    // MAPPINGS
    mapping(uint256 => MetaType) private metaType; // tokenId => metaType
    mapping(address => uint8) private claimed;
    mapping(address => uint8) private wl_claimed;

    ///////////////////////////////////////////////////////////
    //              EVENTS
    // ///////////////////////////////////////////////////////

    event NFTMinted(address minter, uint256 amountRequested, uint256 mintedAmount);

    ///////////////////////////////////////////////////////////
    //              Constructor
    // ///////////////////////////////////////////////////////

    constructor(address _royaltyAddress, uint96 _royaltyBips, string memory _unRevealedUri, address _admin)
        ERC721A("PENGU", "PENGU")
        Ownable(msg.sender)
    {
        setUnRevealedUri(_unRevealedUri);
        setRoyalty(_royaltyAddress, _royaltyBips);
        _mint(_admin, ADMIN_RESERVE);
    }

    ///////////////////////////////////////////////////////////
    //             Modifiers
    // ///////////////////////////////////////////////////////

    modifier isNotBlankURI(string memory _uri) {
        if (bytes(_uri).length == 0) {
            revert PENGU_BLANK_URI();
        }
        _;
    }

    modifier checkZeroAddress(address _address) {
        if (_address == address(0)) {
            revert PENGU_ZERO_ADDRESS();
        }
        _;
    }

    modifier checkZeroPrice(uint256 _price) {
        if (_price == 0) {
            revert PENGU_ZERO_PRICE();
        }
        _;
    }

    modifier isNotPaused() {
        if (saleConfig == SaleConfig.PAUSED) {
            revert PENGU_MINT_PAUSED();
        }
        _;
    }

    modifier isWLSale() {
        if (saleConfig != SaleConfig.WL) {
            revert PENGU_WL_OG_MINT_NOT_ACTIVE();
        }
        _;
    }

    modifier isPublicSale() {
        if (saleConfig != SaleConfig.MINT) {
            revert PENGU_PUBLIC_MINT_NOT_ACTIVE();
        }
        _;
    }

    modifier onlyTokenOwner(uint256 tokenId) {
        if (ownerOf(tokenId) != msg.sender) {
            revert PENGU_NOT_A_TOKEN_OWNER();
        }
        _;
    }

    modifier hasFreeClaim() {
        if (numberOfFreeMint + 1 > FREE_MINT_RESERVE) {
            revert PENGU_FREE_CLAIM_LIMIT_REACHED();
        }

        _;
    }

    modifier hasWlClaimLeft(uint256 _amount) {
        if (numberOfWlMint + _amount > WL_MINT_RESERVE) {
            revert PENGU_WL_CLAIM_LIMIT_REACHED();
        }

        _;
    }

    modifier alreadyClaimed() {
        if (claimed[msg.sender] + 1 > claim_limit) {
            revert PENGU_FREE_MINT_ALREADY_CLAIMED();
        }
        _;
    }

    modifier alreadyWlClaimed(uint256 _amount) {
        if (wl_claimed[msg.sender] + _amount > wl_claim_limit) {
            revert PENGU_WL_MINT_ALREADY_CLAIMED();
        }
        _;
    }

    modifier isInMintTransactionLimit(uint256 _amount) {
        if (_amount > tx_limit) {
            revert PENGU_MINT_TRANSACTION_LIMIT_REACHED();
        }
        _;
    }

    ///////////////////////////////////////////////////////////
    //              Get Functions
    // ///////////////////////////////////////////////////////

    function getSupply() external pure returns (uint256) {
        return SUPPLY;
    }

    function getAdminReserve() external pure returns (uint256) {
        return ADMIN_RESERVE;
    }

    function getFreeMintReserve() external pure returns (uint256) {
        return FREE_MINT_RESERVE;
    }

    function MintPrice() external view returns (uint256) {
        return mint_price;
    }

    function WLMintPrice() external view returns (uint256) {
        return wl_mint_price;
    }

    function MintPriceDiscounted() external view returns (uint256) {
        return mint_price_discounted;
    }

    function WLMintPriceDiscounted() external view returns (uint256) {
        return wl_mint_price_discounted;
    }

    function getSaleConfig() external view returns (SaleConfig) {
        return saleConfig;
    }

    function getMaxLimit() external view returns (uint8) {
        if (saleConfig == SaleConfig.WL) {
            return wl_claim_limit;
        }

        if (saleConfig == SaleConfig.MINT) {
            return tx_limit;
        }

        return claim_limit;
    }

    function isRevealed() external view returns (bool) {
        return revealed;
    }

    function isPaused() external view returns (bool) {
        return saleConfig == SaleConfig.PAUSED;
    }

    function baseURI(uint256 tokenId) internal view returns (string memory) {
        MetaType metadataType = metaType[tokenId];
        if (!revealed) {
            return unRevealedURI;
        }

        if (metadataType == MetaType.TYPE1) {
            return metadataBaseURI;
        }
        return metadataTwoBaseURI;
    }

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        if (!_exists(tokenId)) {
            revert PENGU_NONEXISTENT_TOKEN();
        }

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

    function getOwnerOf(uint256 tokenId) public view returns (address) {
        return ownerOf(tokenId);
    }

    function getStandardPercent() public view returns (uint256) {
        uint256 mintedPercent = (totalSupply() * 10000) / SUPPLY;

        if (mintedPercent >= 7500 && mintedPercent <= 8999) {
            return 60;
        }

        if (mintedPercent >= 9000) {
            return 50;
        }

        return 70;
    }

    function getStandardWLPercent() public view returns (uint256) {
        uint256 mintedPercent = (totalSupply() * 10000) / SUPPLY;

        if (mintedPercent >= 7500 && mintedPercent <= 8999) {
            return 60;
        }

        if (mintedPercent >= 9000) {
            return 50;
        }

        return 70;
    }

    function getDiscountedPercent() public view returns (uint256) {
        uint256 mintedPercent = (totalSupply() * 10000) / SUPPLY;

        if (mintedPercent >= 7500 && mintedPercent <= 8999) {
            return 40;
        }

        if (mintedPercent >= 9000) {
            return 30;
        }

        return 50;
    }

    function getDiscountedWLPercent() public view returns (uint256) {
        uint256 mintedPercent = (totalSupply() * 10000) / SUPPLY;

        if (mintedPercent >= 7500 && mintedPercent <= 8999) {
            return 40;
        }

        if (mintedPercent >= 9000) {
            return 30;
        }

        return 50;
    }

    function getRandomNum(uint256 upper, uint256 numDay) internal returns (uint256) {
        nonce++;
        return uint256(keccak256(abi.encodePacked(block.timestamp + numDay, block.prevrandao, nonce))) % upper + 1;
    }

    function getSuccessNum(uint256 _amount, MetaType meta) internal returns (uint8) {
        uint8 numToMint;
        uint256 mintPercent = meta == MetaType.TYPE1 ? getStandardPercent() : getDiscountedPercent();
        for (uint256 i = 0; i < _amount; i++) {
            uint256 num = getRandomNum(100, i + 1 days);
            if (num <= mintPercent) {
                numToMint++;
            }
        }

        return numToMint;
    }

    function getSuccessNumWL(uint256 _amount, MetaType meta) internal returns (uint8) {
        uint8 numToMint;
        uint256 mintPercent = meta == MetaType.TYPE1 ? getStandardWLPercent() : getDiscountedWLPercent();
        for (uint256 i = 0; i < _amount; i++) {
            uint256 num = getRandomNum(100, i + 1 days);
            if (num <= mintPercent) {
                numToMint++;
            }
        }

        return numToMint;
    }

    ///////////////////////////////////////////////////////////
    //              Set Functions
    // ///////////////////////////////////////////////////////

    function setRoyalty(address _receiver, uint96 _royaltyFeeInBips) public onlyOwner checkZeroAddress(_receiver) {
        _setDefaultRoyalty(_receiver, _royaltyFeeInBips);
    }

    function setSaleConfigToMint() external onlyOwner {
        saleConfig = SaleConfig.MINT;
    }

    function setSaleConfigToPause() external onlyOwner {
        saleConfig = SaleConfig.PAUSED;
    }

    function setSaleConfigToWLMint() external onlyOwner {
        saleConfig = SaleConfig.WL;
    }

    function setReveal(bool value) external onlyOwner {
        revealed = value;
    }

    function setUnRevealedUri(string memory _unRevealedUri) public onlyOwner isNotBlankURI(_unRevealedUri) {
        unRevealedURI = _unRevealedUri;
    }

    function setMetaDataURI(string calldata _metadataBaseURI) external onlyOwner isNotBlankURI(_metadataBaseURI) {
        metadataBaseURI = _metadataBaseURI;
    }

    function setMintPrice(uint256 _price) external onlyOwner checkZeroPrice(_price) {
        mint_price = _price;
    }

    function setMintPriceDiscounted(uint256 _price) external onlyOwner checkZeroPrice(_price) {
        mint_price_discounted = _price;
    }

    function toggleMetadata(uint256 tokenId) external onlyTokenOwner(tokenId) {
        metaType[tokenId] = metaType[tokenId] == MetaType.TYPE1 ? MetaType.TYPE2 : MetaType.TYPE1;
    }

    function setMetaDataTwoURI(string calldata _metadataTwoBaseURI)
        external
        onlyOwner
        isNotBlankURI(_metadataTwoBaseURI)
    {
        metadataTwoBaseURI = _metadataTwoBaseURI;
    }

    function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
        if (_merkleRoot.length == 0) {
            revert PENGU_INVALID_MERKLE_ROOT();
        }
        merkleRoot = _merkleRoot;
    }

    function setWLMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
        if (_merkleRoot.length == 0) {
            revert PENGU_INVALID_MERKLE_ROOT();
        }
        wl_merkleRoot = _merkleRoot;
    }

    ///////////////////////////////////////////////////////////
    //              Mint Functions
    // ///////////////////////////////////////////////////////

    function mint(uint256 _amount) external payable isNotPaused isPublicSale isInMintTransactionLimit(_amount) {
        if (msg.value < mint_price * _amount) {
            revert PENGU_INSUFFICIENT_FUNDS();
        }
        uint8 numToMint = getSuccessNum(_amount, MetaType.TYPE1);
        if (numToMint > 0) _mint(msg.sender, numToMint);
        emit NFTMinted(msg.sender, _amount, numToMint);
    }

    function mintTypeTwo(uint256 _amount) external payable isNotPaused isPublicSale isInMintTransactionLimit(_amount) {
        if (msg.value < mint_price_discounted * _amount) {
            revert PENGU_INSUFFICIENT_FUNDS();
        }
        uint8 numToMint = getSuccessNum(_amount, MetaType.TYPE2);
        if (numToMint > 0) _mint(msg.sender, numToMint);
        emit NFTMinted(msg.sender, _amount, numToMint);
    }

    function wl_mint(uint256 _amount, bytes32[] calldata _proof)
        external
        payable
        isNotPaused
        isWLSale
        hasWlClaimLeft(_amount)
        alreadyWlClaimed(_amount)
        isInMintTransactionLimit(_amount)
    {
        if (!verifyWL(_proof, msg.sender)) {
            revert PENGU_NOT_VERIFIED();
        }
        if (msg.value < wl_mint_price * _amount) {
            revert PENGU_INSUFFICIENT_FUNDS();
        }
        uint8 numToMint = getSuccessNumWL(_amount, MetaType.TYPE1);
        if (numToMint > 0) {
            numberOfWlMint += numToMint;
            wl_claimed[msg.sender] += uint8(_amount);
            _mint(msg.sender, numToMint);
        }
        emit NFTMinted(msg.sender, _amount, numToMint);
    }

    function wl_mintTypeTwo(uint256 _amount, bytes32[] calldata _proof)
        external
        payable
        isNotPaused
        isWLSale
        hasWlClaimLeft(_amount)
        alreadyWlClaimed(_amount)
        isInMintTransactionLimit(_amount)
    {
        if (!verifyWL(_proof, msg.sender)) {
            revert PENGU_NOT_VERIFIED();
        }
        if (msg.value < wl_mint_price_discounted * _amount) {
            revert PENGU_INSUFFICIENT_FUNDS();
        }
        uint8 numToMint = getSuccessNumWL(_amount, MetaType.TYPE2);
        if (numToMint > 0) {
            numberOfWlMint += numToMint;
            wl_claimed[msg.sender] += uint8(_amount);
            _mint(msg.sender, numToMint);
        }
        emit NFTMinted(msg.sender, _amount, numToMint);
    }

    function claim(bytes32[] calldata _proof) external payable isNotPaused isWLSale hasFreeClaim alreadyClaimed {
        if (!verify(_proof, msg.sender)) {
            revert PENGU_NOT_VERIFIED();
        }
        numberOfFreeMint++;
        claimed[msg.sender]++;
        _mint(msg.sender, 1);
        emit NFTMinted(msg.sender, 1, 1);
    }

    ///////////////////////////////////////////////////////////
    //              Others Functions
    // ///////////////////////////////////////////////////////

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, ERC2981) returns (bool) {
        return ERC721A.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId);
    }

    function verify(bytes32[] calldata _proof, address _sender) internal view returns (bool) {
        return MerkleProof.verify(_proof, merkleRoot, keccak256(abi.encodePacked(_sender)));
    }

    function verifyWL(bytes32[] calldata _proof, address _sender) internal view returns (bool) {
        return MerkleProof.verify(_proof, wl_merkleRoot, keccak256(abi.encodePacked(_sender)));
    }

    function withdrawFunds() external onlyOwner {
        if (address(this).balance == 0) {
            revert PENGU_NO_FUNDS_TO_WITHDRAW();
        }
        (bool success,) = owner().call{value: address(this).balance}("");
        if (!success) {
            revert PENGU_WITHDRAWAL_FAILED();
        }
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_royaltyAddress","type":"address"},{"internalType":"uint96","name":"_royaltyBips","type":"uint96"},{"internalType":"string","name":"_unRevealedUri","type":"string"},{"internalType":"address","name":"_admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidDefaultRoyalty","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidDefaultRoyaltyReceiver","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidTokenRoyalty","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidTokenRoyaltyReceiver","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"PENGU_BLANK_URI","type":"error"},{"inputs":[],"name":"PENGU_FREE_CLAIM_LIMIT_REACHED","type":"error"},{"inputs":[],"name":"PENGU_FREE_MINT_ALREADY_CLAIMED","type":"error"},{"inputs":[],"name":"PENGU_INSUFFICIENT_FUNDS","type":"error"},{"inputs":[],"name":"PENGU_INVALID_MERKLE_ROOT","type":"error"},{"inputs":[],"name":"PENGU_MINT_PAUSED","type":"error"},{"inputs":[],"name":"PENGU_MINT_TRANSACTION_LIMIT_REACHED","type":"error"},{"inputs":[],"name":"PENGU_NONEXISTENT_TOKEN","type":"error"},{"inputs":[],"name":"PENGU_NOT_A_TOKEN_OWNER","type":"error"},{"inputs":[],"name":"PENGU_NOT_VERIFIED","type":"error"},{"inputs":[],"name":"PENGU_NO_FUNDS_TO_WITHDRAW","type":"error"},{"inputs":[],"name":"PENGU_PUBLIC_MINT_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"PENGU_WITHDRAWAL_FAILED","type":"error"},{"inputs":[],"name":"PENGU_WL_CLAIM_LIMIT_REACHED","type":"error"},{"inputs":[],"name":"PENGU_WL_MINT_ALREADY_CLAIMED","type":"error"},{"inputs":[],"name":"PENGU_WL_OG_MINT_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"PENGU_ZERO_ADDRESS","type":"error"},{"inputs":[],"name":"PENGU_ZERO_PRICE","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"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":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountRequested","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintedAmount","type":"uint256"}],"name":"NFTMinted","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":[],"name":"MintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MintPriceDiscounted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WLMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WLMintPriceDiscounted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAdminReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDiscountedPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDiscountedWLPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFreeMintReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getMaxLimit","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getOwnerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSaleConfig","outputs":[{"internalType":"enum PENGU.SaleConfig","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStandardPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStandardWLPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRevealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintTypeTwo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"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":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_metadataTwoBaseURI","type":"string"}],"name":"setMetaDataTwoURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_metadataBaseURI","type":"string"}],"name":"setMetaDataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setMintPriceDiscounted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"value","type":"bool"}],"name":"setReveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint96","name":"_royaltyFeeInBips","type":"uint96"}],"name":"setRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setSaleConfigToMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setSaleConfigToPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setSaleConfigToWLMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_unRevealedUri","type":"string"}],"name":"setUnRevealedUri","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setWLMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"toggleMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"wl_mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"wl_mintTypeTwo","outputs":[],"stateMutability":"payable","type":"function"}]

60806040525f600b5566470de4df820000600f55663e2c284391c000601081905560115566354a6ba7a180006012556013805466ffffffffffffff1916620a02011790553480156200004f575f80fd5b5060405162003380380380620033808339810160408190526200007291620003dd565b60408051808201825260058082526450454e475560d81b602080840182905284518086019095529184529083015233916002620000b0838262000579565b506003620000bf828262000579565b505f805550506001600160a01b038116620000f457604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b620000ff816200012e565b506200010b826200017f565b620001178484620001bf565b62000124816096620001fe565b5050505062000645565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b62000189620002d6565b8080515f03620001ac576040516314a565f360e01b815260040160405180910390fd5b600e620001ba838262000579565b505050565b620001c9620002d6565b816001600160a01b038116620001f257604051634e22aed760e01b815260040160405180910390fd5b620001ba838362000307565b5f805490829003620002235760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b0383165f8181526005602090815260408083208054680100000000000000018802019055848352600490915281206001851460e11b4260a01b178317905582840190839083905f80516020620033608339815191528180a4600183015b818114620002ad5780835f5f80516020620033608339815191525f80a460010162000287565b50815f03620002ce57604051622e076360e81b815260040160405180910390fd5b5f5550505050565b6008546001600160a01b03163314620003055760405163118cdaa760e01b8152336004820152602401620000eb565b565b6127106001600160601b0382168110156200034857604051636f483d0960e01b81526001600160601b038316600482015260248101829052604401620000eb565b6001600160a01b0383166200037357604051635b6cc80560e11b81525f6004820152602401620000eb565b50604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600955565b80516001600160a01b0381168114620003c4575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f805f8060808587031215620003f1575f80fd5b620003fc85620003ad565b602086810151919550906001600160601b03811681146200041b575f80fd5b60408701519094506001600160401b038082111562000438575f80fd5b818801915088601f8301126200044c575f80fd5b815181811115620004615762000461620003c9565b604051601f8201601f19908116603f011681019083821181831017156200048c576200048c620003c9565b816040528281528b86848701011115620004a4575f80fd5b5f93505b82841015620004c75784840186015181850187015292850192620004a8565b5f868483010152809750505050505050620004e560608601620003ad565b905092959194509250565b600181811c908216806200050557607f821691505b6020821081036200052457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115620001ba57805f5260205f20601f840160051c81016020851015620005515750805b601f840160051c820191505b8181101562000572575f81556001016200055d565b5050505050565b81516001600160401b03811115620005955762000595620003c9565b620005ad81620005a68454620004f0565b846200052a565b602080601f831160018114620005e3575f8415620005cb5750858301515b5f19600386901b1c1916600185901b1785556200063d565b5f85815260208120601f198616915b828110156200061357888601518255948401946001909101908401620005f2565b50858210156200063157878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b612d0d80620006535f395ff3fe60806040526004361061030d575f3560e01c8063712ff68e116101a3578063b187bd26116100f2578063e359895711610092578063f2fde38b1161006d578063f2fde38b14610809578063f4a0a52814610828578063f83425df14610847578063fdbf9ef21461085a575f80fd5b8063e3598957146107b7578063e985e9c5146107cb578063ef90a594146107ea575f80fd5b8063b88d4fde116100cd578063b88d4fde14610739578063c87b56dd1461074c578063cea943ee1461076b578063df6d484314610791575f80fd5b8063b187bd2614610712578063b385ff8d1461035b578063b391c50814610726575f80fd5b80638f2fc60b1161015d5780639ddafbda116101385780639ddafbda146106c15780639e7fa3b514610413578063a0712d68146106e0578063a22cb465146106f3575f80fd5b80638f2fc60b1461067a57806395d89b41146106995780639946f6d9146106ad575f80fd5b8063712ff68e146105d9578063715018a6146105ec5780637cb64759146106005780637d44fd111461061f578063836387101461063e5780638da5cb5b1461065d575f80fd5b80632a3f300c1161025f57806342842e0e116102195780636352211e116101f45780636352211e146105745780636c9c2faf146105935780636fedcf20146105a757806370a08231146105ba575f80fd5b806342842e0e1461052f578063533e8ca51461054257806354214f6914610556575f80fd5b80632a3f300c1461048c5780632a55205a146104ab57806336cee2c0146104e957806337c8c5da146104fc5780633d46181c146105105780634175c76a146104e9575f80fd5b806313596014116102ca57806323b872dd116102a557806323b872dd1461042757806324600fc31461043a5780632532ae481461044e578063271ed62c1461046d575f80fd5b806313596014146103e857806318160ddd146103fc5780631f67428e14610413575f80fd5b806301ffc9a7146103115780630468ea76146103455780630554968f1461035b57806306fdde031461037d578063081812fc1461039e578063095ea7b3146103d5575b5f80fd5b34801561031c575f80fd5b5061033061032b3660046124b2565b61086e565b60405190151581526020015b60405180910390f35b348015610350575f80fd5b5061035961088d565b005b348015610366575f80fd5b5061036f6108b4565b60405190815260200161033c565b348015610388575f80fd5b50610391610917565b60405161033c919061251a565b3480156103a9575f80fd5b506103bd6103b836600461252c565b6109a7565b6040516001600160a01b03909116815260200161033c565b6103596103e336600461255e565b6109e9565b3480156103f3575f80fd5b50610359610a87565b348015610407575f80fd5b506001545f540361036f565b34801561041e575f80fd5b5061036f610aab565b610359610435366004612586565b610b0e565b348015610445575f80fd5b50610359610c9e565b348015610459575f80fd5b5061035961046836600461252c565b610d4a565b348015610478575f80fd5b50610359610487366004612646565b610ddb565b348015610497575f80fd5b506103596104a636600461269a565b610e16565b3480156104b6575f80fd5b506104ca6104c53660046126b3565b610e3f565b604080516001600160a01b03909316835260208301919091520161033c565b3480156104f4575f80fd5b50609661036f565b348015610507575f80fd5b5060105461036f565b34801561051b575f80fd5b5061035961052a3660046126d3565b610eeb565b61035961053d366004612586565b610f5d565b34801561054d575f80fd5b5060115461036f565b348015610561575f80fd5b50601354600160301b900460ff16610330565b34801561057f575f80fd5b506103bd61058e36600461252c565b610f77565b34801561059e575f80fd5b50611e6161036f565b6103596105b5366004612780565b610f81565b3480156105c5575f80fd5b5061036f6105d43660046127c8565b6111e8565b6103596105e7366004612780565b611235565b3480156105f7575f80fd5b506103596113c7565b34801561060b575f80fd5b5061035961061a36600461252c565b6113da565b34801561062a575f80fd5b5061035961063936600461252c565b6113e7565b348015610649575f80fd5b506103bd61065836600461252c565b6113f4565b348015610668575f80fd5b506008546001600160a01b03166103bd565b348015610685575f80fd5b506103596106943660046127e1565b6113fe565b3480156106a4575f80fd5b50610391611438565b3480156106b8575f80fd5b5060125461036f565b3480156106cc575f80fd5b506103596106db3660046126d3565b611447565b6103596106ee36600461252c565b6114b3565b3480156106fe575f80fd5b5061035961070d366004612821565b6115f4565b34801561071d575f80fd5b5061033061165f565b610359610734366004612852565b611685565b610359610747366004612891565b611865565b348015610757575f80fd5b5061039161076636600461252c565b6118a9565b348015610776575f80fd5b50601354600160281b900460ff1660405161033c919061291c565b34801561079c575f80fd5b506107a561194a565b60405160ff909116815260200161033c565b3480156107c2575f80fd5b506103596119be565b3480156107d6575f80fd5b506103306107e5366004612942565b6119e1565b3480156107f5575f80fd5b5061035961080436600461252c565b611a0e565b348015610814575f80fd5b506103596108233660046127c8565b611a3d565b348015610833575f80fd5b5061035961084236600461252c565b611a7c565b61035961085536600461252c565b611aab565b348015610865575f80fd5b50600f5461036f565b5f61087882611b8e565b80610887575061088782611bdb565b92915050565b610895611c0f565b601380546001919065ff00000000001916600160281b835b0217905550565b5f80611e616108c56001545f540390565b6108d19061271061297e565b6108db91906129a9565b9050611d4c81101580156108f157506123278111155b156108fe57602891505090565b612328811061090f57601e91505090565b603291505090565b606060028054610926906129bc565b80601f0160208091040260200160405190810160405280929190818152602001828054610952906129bc565b801561099d5780601f106109745761010080835404028352916020019161099d565b820191905f5260205f20905b81548152906001019060200180831161098057829003601f168201915b5050505050905090565b5f6109b182611c3c565b6109ce576040516333d1c03960e21b815260040160405180910390fd5b505f908152600660205260409020546001600160a01b031690565b5f6109f382610f77565b9050336001600160a01b03821614610a2c57610a0f81336119e1565b610a2c576040516367d9dca160e11b815260040160405180910390fd5b5f8281526006602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610a8f611c0f565b601380546002919065ff00000000001916600160281b836108ad565b5f80611e61610abc6001545f540390565b610ac89061271061297e565b610ad291906129a9565b9050611d4c8110158015610ae857506123278111155b15610af557603c91505090565b6123288110610b0657603291505090565b604691505090565b5f610b1882611c61565b9050836001600160a01b0316816001600160a01b031614610b4b5760405162a1148160e81b815260040160405180910390fd5b5f8281526006602052604090208054338082146001600160a01b03881690911417610b9757610b7a86336119e1565b610b9757604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b038516610bbe57604051633a954ecd60e21b815260040160405180910390fd5b8015610bc8575f82555b6001600160a01b038681165f9081526005602052604080822080545f19019055918716808252919020805460010190554260a01b17600160e11b175f85815260046020526040812091909155600160e11b84169003610c5457600184015f818152600460205260408120549003610c52575f548114610c52575f8181526004602052604090208490555b505b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b505050505050565b610ca6611c0f565b475f03610cc6576040516312c002cf60e11b815260040160405180910390fd5b5f610cd96008546001600160a01b031690565b6001600160a01b0316476040515f6040518083038185875af1925050503d805f8114610d20576040519150601f19603f3d011682016040523d82523d5f602084013e610d25565b606091505b5050905080610d475760405163a4a6037f60e01b815260040160405180910390fd5b50565b8033610d5582610f77565b6001600160a01b031614610d7c5760405163074af00f60e31b815260040160405180910390fd5b5f8281526016602052604081205460ff166001811115610d9e57610d9e612908565b14610da9575f610dac565b60015b5f838152601660205260409020805460ff191660018381811115610dd257610dd2612908565b02179055505050565b610de3611c0f565b8080515f03610e05576040516314a565f360e01b815260040160405180910390fd5b600e610e118382612a3f565b505050565b610e1e611c0f565b60138054911515600160301b0266ff00000000000019909216919091179055565b5f828152600a602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610eb35750604080518082019091526009546001600160a01b0381168252600160a01b90046001600160601b031660208201525b60208101515f9061271090610ed1906001600160601b03168761297e565b610edb91906129a9565b91519350909150505b9250929050565b610ef3611c0f565b81818080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920182905250845190039250610f4a915050576040516314a565f360e01b815260040160405180910390fd5b600c610f57838583612afb565b50505050565b610e1183838360405180602001604052805f815250611865565b5f61088782611c61565b5f601354600160281b900460ff166002811115610fa057610fa0612908565b03610fbe57604051631e82594960e21b815260040160405180910390fd5b6001601354600160281b900460ff166002811115610fde57610fde612908565b14610ffc5760405163d88be7df60e01b815260040160405180910390fd5b60135483906103e89061101b908390640100000000900460ff16612bb5565b111561103a576040516365264a7f60e11b815260040160405180910390fd5b601354335f90815260186020526040902054859160ff61010090910481169161106591849116612bb5565b11156110845760405163e48a8d6760e01b815260040160405180910390fd5b601354859062010000900460ff168111156110b25760405163422c9d9f60e11b815260040160405180910390fd5b6110bd858533611cc2565b6110da576040516364b6a9c960e01b815260040160405180910390fd5b856012546110e8919061297e565b34101561110857604051637470432d60e01b815260040160405180910390fd5b5f611114876001611d41565b905060ff81161561119d5780601360048282829054906101000a900460ff1661113d9190612bc8565b82546101009290920a60ff818102199093169183160217909155335f90815260186020526040812080548b9450909261117891859116612bc8565b92506101000a81548160ff021916908360ff16021790555061119d338260ff16611dbf565b604080513381526020810189905260ff83168183015290517f3a8a89b59a31c39a36febecb987e0657ab7b7c73b60ebacb44dcb9886c2d5c8a9181900360600190a150505050505050565b5f6001600160a01b038216611210576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b03165f9081526005602052604090205467ffffffffffffffff1690565b5f601354600160281b900460ff16600281111561125457611254612908565b0361127257604051631e82594960e21b815260040160405180910390fd5b6001601354600160281b900460ff16600281111561129257611292612908565b146112b05760405163d88be7df60e01b815260040160405180910390fd5b60135483906103e8906112cf908390640100000000900460ff16612bb5565b11156112ee576040516365264a7f60e11b815260040160405180910390fd5b601354335f90815260186020526040902054859160ff61010090910481169161131991849116612bb5565b11156113385760405163e48a8d6760e01b815260040160405180910390fd5b601354859062010000900460ff168111156113665760405163422c9d9f60e11b815260040160405180910390fd5b611371858533611cc2565b61138e576040516364b6a9c960e01b815260040160405180910390fd5b8560105461139c919061297e565b3410156113bc57604051637470432d60e01b815260040160405180910390fd5b5f611114875f611d41565b6113cf611c0f565b6113d85f611eb7565b565b6113e2611c0f565b601455565b6113ef611c0f565b601555565b5f61088782610f77565b611406611c0f565b816001600160a01b03811661142e57604051634e22aed760e01b815260040160405180910390fd5b610e118383611f08565b606060038054610926906129bc565b61144f611c0f565b81818080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052508451900392506114a6915050576040516314a565f360e01b815260040160405180910390fd5b600d610f57838583612afb565b5f601354600160281b900460ff1660028111156114d2576114d2612908565b036114f057604051631e82594960e21b815260040160405180910390fd5b6002601354600160281b900460ff16600281111561151057611510612908565b1461152e5760405163c7aac1b760e01b815260040160405180910390fd5b601354819062010000900460ff1681111561155c5760405163422c9d9f60e11b815260040160405180910390fd5b81600f5461156a919061297e565b34101561158a57604051637470432d60e01b815260040160405180910390fd5b5f611595835f611faa565b905060ff8116156115ad576115ad338260ff16611dbf565b604080513381526020810185905260ff83168183015290517f3a8a89b59a31c39a36febecb987e0657ab7b7c73b60ebacb44dcb9886c2d5c8a9181900360600190a1505050565b335f8181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b5f80601354600160281b900460ff16600281111561167f5761167f612908565b14905090565b5f601354600160281b900460ff1660028111156116a4576116a4612908565b036116c257604051631e82594960e21b815260040160405180910390fd5b6001601354600160281b900460ff1660028111156116e2576116e2612908565b146117005760405163d88be7df60e01b815260040160405180910390fd5b60135460969061171b906301000000900460ff166001612bc8565b60ff16111561173d57604051636c08431160e01b815260040160405180910390fd5b601354335f9081526017602052604090205460ff9182169161176191166001612bc8565b60ff161115611783576040516382c774b760e01b815260040160405180910390fd5b61178e828233612019565b6117ab576040516364b6a9c960e01b815260040160405180910390fd5b601380546301000000900460ff169060036117c583612be1565b82546101009290920a60ff818102199093169183160217909155335f908152601760205260408120805490921692506117fd83612be1565b91906101000a81548160ff021916908360ff16021790555050611821336001611dbf565b604080513381526001602082018190528183015290517f3a8a89b59a31c39a36febecb987e0657ab7b7c73b60ebacb44dcb9886c2d5c8a9181900360600190a15050565b611870848484610b0e565b6001600160a01b0383163b15610f575761188c84848484612079565b610f57576040516368d2bf6b60e11b815260040160405180910390fd5b60606118b482611c3c565b6118d1576040516311ee148d60e01b815260040160405180910390fd5b5f6118db83612160565b90505f8151116118f95760405180602001604052805f815250611943565b8061190384612249565b60405180604001604052806005815260200164173539b7b760d91b81525060405160200161193393929190612bff565b6040516020818303038152906040525b9392505050565b5f6001601354600160281b900460ff16600281111561196b5761196b612908565b0361197f5750601354610100900460ff1690565b6002601354600160281b900460ff16600281111561199f5761199f612908565b036119b4575060135462010000900460ff1690565b5060135460ff1690565b6119c6611c0f565b601380545f919065ff00000000001916600160281b836108ad565b6001600160a01b039182165f90815260076020908152604080832093909416825291909152205460ff1690565b611a16611c0f565b80805f03611a37576040516301fb565360e71b815260040160405180910390fd5b50601155565b611a45611c0f565b6001600160a01b038116611a7357604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b610d4781611eb7565b611a84611c0f565b80805f03611aa5576040516301fb565360e71b815260040160405180910390fd5b50600f55565b5f601354600160281b900460ff166002811115611aca57611aca612908565b03611ae857604051631e82594960e21b815260040160405180910390fd5b6002601354600160281b900460ff166002811115611b0857611b08612908565b14611b265760405163c7aac1b760e01b815260040160405180910390fd5b601354819062010000900460ff16811115611b545760405163422c9d9f60e11b815260040160405180910390fd5b81601154611b62919061297e565b341015611b8257604051637470432d60e01b815260040160405180910390fd5b5f611595836001611faa565b5f6301ffc9a760e01b6001600160e01b031983161480611bbe57506380ac58cd60e01b6001600160e01b03198316145b806108875750506001600160e01b031916635b5e139f60e01b1490565b5f6001600160e01b0319821663152a902d60e11b148061088757506301ffc9a760e01b6001600160e01b0319831614610887565b6008546001600160a01b031633146113d85760405163118cdaa760e01b8152336004820152602401611a6a565b5f8054821080156108875750505f90815260046020526040902054600160e01b161590565b5f815f54811015611ca9575f8181526004602052604081205490600160e01b82169003611ca7575b805f0361194357505f19015f81815260046020526040902054611c89565b505b604051636f96cda160e11b815260040160405180910390fd5b5f611d398484808060200260200160405190810160405280939291908181526020018383602002808284375f92019190915250506015546040516bffffffffffffffffffffffff19606089901b16602082015290925060340190505b604051602081830303815290604052805190602001206122d9565b949350505050565b5f808080846001811115611d5757611d57612908565b14611d6957611d646108b4565b611d71565b611d71610aab565b90505f5b85811015611db5575f611d956064611d908462015180612bb5565b6122ee565b9050828111611dac5783611da881612be1565b9450505b50600101611d75565b5090949350505050565b5f805490829003611de35760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b0383165f8181526005602090815260408083208054680100000000000000018802019055848352600490915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b818114611e8f5780835f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4600101611e59565b50815f03611eaf57604051622e076360e81b815260040160405180910390fd5b5f5550505050565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6127106001600160601b038216811015611f4757604051636f483d0960e01b81526001600160601b038316600482015260248101829052604401611a6a565b6001600160a01b038316611f7057604051635b6cc80560e11b81525f6004820152602401611a6a565b50604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600955565b5f808080846001811115611fc057611fc0612908565b14611fd257611fcd6108b4565b611fda565b611fda610aab565b90505f5b85811015611db5575f611ff96064611d908462015180612bb5565b9050828111612010578361200c81612be1565b9450505b50600101611fde565b5f611d398484808060200260200160405190810160405280939291908181526020018383602002808284375f92019190915250506014546040516bffffffffffffffffffffffff19606089901b1660208201529092506034019050611d1e565b604051630a85bd0160e11b81525f906001600160a01b0385169063150b7a02906120ad903390899088908890600401612c41565b6020604051808303815f875af19250505080156120e7575060408051601f3d908101601f191682019092526120e491810190612c7d565b60015b612143573d808015612114576040519150601f19603f3d011682016040523d82523d5f602084013e612119565b606091505b5080515f0361213b576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b5f8181526016602052604090205460135460609160ff90811691600160301b90041661221757600e8054612193906129bc565b80601f01602080910402602001604051908101604052809291908181526020018280546121bf906129bc565b801561220a5780601f106121e15761010080835404028352916020019161220a565b820191905f5260205f20905b8154815290600101906020018083116121ed57829003601f168201915b5050505050915050919050565b5f81600181111561222a5761222a612908565b0361223c57600c8054612193906129bc565b600d8054612193906129bc565b60605f61225583612358565b60010190505f8167ffffffffffffffff811115612274576122746125bf565b6040519080825280601f01601f19166020018201604052801561229e576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846122a857509392505050565b5f826122e5858461242f565b14949350505050565b600b80545f91826122fe83612c98565b9091555083905061230f8342612bb5565b600b5460408051602081019390935244908301526060820152608001604051602081830303815290604052805190602001205f1c61234d9190612cb0565b611943906001612bb5565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106123965772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106123c2576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106123e057662386f26fc10000830492506010015b6305f5e10083106123f8576305f5e100830492506008015b612710831061240c57612710830492506004015b6064831061241e576064830492506002015b600a83106108875760010192915050565b5f81815b84518110156124695761245f8286838151811061245257612452612cc3565b6020026020010151612471565b9150600101612433565b509392505050565b5f81831061248b575f828152602084905260409020611943565b5f838152602083905260409020611943565b6001600160e01b031981168114610d47575f80fd5b5f602082840312156124c2575f80fd5b81356119438161249d565b5f5b838110156124e75781810151838201526020016124cf565b50505f910152565b5f81518084526125068160208601602086016124cd565b601f01601f19169290920160200192915050565b602081525f61194360208301846124ef565b5f6020828403121561253c575f80fd5b5035919050565b80356001600160a01b0381168114612559575f80fd5b919050565b5f806040838503121561256f575f80fd5b61257883612543565b946020939093013593505050565b5f805f60608486031215612598575f80fd5b6125a184612543565b92506125af60208501612543565b9150604084013590509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f67ffffffffffffffff808411156125ed576125ed6125bf565b604051601f8501601f19908116603f01168101908282118183101715612615576126156125bf565b8160405280935085815286868601111561262d575f80fd5b858560208301375f602087830101525050509392505050565b5f60208284031215612656575f80fd5b813567ffffffffffffffff81111561266c575f80fd5b8201601f8101841361267c575f80fd5b611d39848235602084016125d3565b80358015158114612559575f80fd5b5f602082840312156126aa575f80fd5b6119438261268b565b5f80604083850312156126c4575f80fd5b50508035926020909101359150565b5f80602083850312156126e4575f80fd5b823567ffffffffffffffff808211156126fb575f80fd5b818501915085601f83011261270e575f80fd5b81358181111561271c575f80fd5b86602082850101111561272d575f80fd5b60209290920196919550909350505050565b5f8083601f84011261274f575f80fd5b50813567ffffffffffffffff811115612766575f80fd5b6020830191508360208260051b8501011115610ee4575f80fd5b5f805f60408486031215612792575f80fd5b83359250602084013567ffffffffffffffff8111156127af575f80fd5b6127bb8682870161273f565b9497909650939450505050565b5f602082840312156127d8575f80fd5b61194382612543565b5f80604083850312156127f2575f80fd5b6127fb83612543565b915060208301356001600160601b0381168114612816575f80fd5b809150509250929050565b5f8060408385031215612832575f80fd5b61283b83612543565b91506128496020840161268b565b90509250929050565b5f8060208385031215612863575f80fd5b823567ffffffffffffffff811115612879575f80fd5b6128858582860161273f565b90969095509350505050565b5f805f80608085870312156128a4575f80fd5b6128ad85612543565b93506128bb60208601612543565b925060408501359150606085013567ffffffffffffffff8111156128dd575f80fd5b8501601f810187136128ed575f80fd5b6128fc878235602084016125d3565b91505092959194509250565b634e487b7160e01b5f52602160045260245ffd5b602081016003831061293c57634e487b7160e01b5f52602160045260245ffd5b91905290565b5f8060408385031215612953575f80fd5b61295c83612543565b915061284960208401612543565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176108875761088761296a565b634e487b7160e01b5f52601260045260245ffd5b5f826129b7576129b7612995565b500490565b600181811c908216806129d057607f821691505b6020821081036129ee57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115610e1157805f5260205f20601f840160051c81016020851015612a195750805b601f840160051c820191505b81811015612a38575f8155600101612a25565b5050505050565b815167ffffffffffffffff811115612a5957612a596125bf565b612a6d81612a6784546129bc565b846129f4565b602080601f831160018114612aa0575f8415612a895750858301515b5f19600386901b1c1916600185901b178555610c96565b5f85815260208120601f198616915b82811015612ace57888601518255948401946001909101908401612aaf565b5085821015612aeb57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b67ffffffffffffffff831115612b1357612b136125bf565b612b2783612b2183546129bc565b836129f4565b5f601f841160018114612b58575f8515612b415750838201355b5f19600387901b1c1916600186901b178355612a38565b5f83815260208120601f198716915b82811015612b875786850135825560209485019460019092019101612b67565b5086821015612ba3575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b808201808211156108875761088761296a565b60ff81811683821601908111156108875761088761296a565b5f60ff821660ff8103612bf657612bf661296a565b60010192915050565b5f8451612c108184602089016124cd565b845190830190612c248183602089016124cd565b8451910190612c378183602088016124cd565b0195945050505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190525f90612c73908301846124ef565b9695505050505050565b5f60208284031215612c8d575f80fd5b81516119438161249d565b5f60018201612ca957612ca961296a565b5060010190565b5f82612cbe57612cbe612995565b500690565b634e487b7160e01b5f52603260045260245ffdfea264697066735822122083b53e511b958f184a3c37ba355e8927dd77d92e102a9452092a14719879341164736f6c63430008170033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef00000000000000000000000039d6a3647acdb9cd25f0d0eb93e03341f288ba1200000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000128cd513dc57d8e5ceeb098e584545fb4c340ee000000000000000000000000000000000000000000000000000000000000005968747470733a2f2f6261667962656961373562703370787332676d6c776675767762707277377a716f666475636272716e666c78633565736363746766617833346f712e697066732e6e667473746f726167652e6c696e6b2f00000000000000

Deployed Bytecode

0x60806040526004361061030d575f3560e01c8063712ff68e116101a3578063b187bd26116100f2578063e359895711610092578063f2fde38b1161006d578063f2fde38b14610809578063f4a0a52814610828578063f83425df14610847578063fdbf9ef21461085a575f80fd5b8063e3598957146107b7578063e985e9c5146107cb578063ef90a594146107ea575f80fd5b8063b88d4fde116100cd578063b88d4fde14610739578063c87b56dd1461074c578063cea943ee1461076b578063df6d484314610791575f80fd5b8063b187bd2614610712578063b385ff8d1461035b578063b391c50814610726575f80fd5b80638f2fc60b1161015d5780639ddafbda116101385780639ddafbda146106c15780639e7fa3b514610413578063a0712d68146106e0578063a22cb465146106f3575f80fd5b80638f2fc60b1461067a57806395d89b41146106995780639946f6d9146106ad575f80fd5b8063712ff68e146105d9578063715018a6146105ec5780637cb64759146106005780637d44fd111461061f578063836387101461063e5780638da5cb5b1461065d575f80fd5b80632a3f300c1161025f57806342842e0e116102195780636352211e116101f45780636352211e146105745780636c9c2faf146105935780636fedcf20146105a757806370a08231146105ba575f80fd5b806342842e0e1461052f578063533e8ca51461054257806354214f6914610556575f80fd5b80632a3f300c1461048c5780632a55205a146104ab57806336cee2c0146104e957806337c8c5da146104fc5780633d46181c146105105780634175c76a146104e9575f80fd5b806313596014116102ca57806323b872dd116102a557806323b872dd1461042757806324600fc31461043a5780632532ae481461044e578063271ed62c1461046d575f80fd5b806313596014146103e857806318160ddd146103fc5780631f67428e14610413575f80fd5b806301ffc9a7146103115780630468ea76146103455780630554968f1461035b57806306fdde031461037d578063081812fc1461039e578063095ea7b3146103d5575b5f80fd5b34801561031c575f80fd5b5061033061032b3660046124b2565b61086e565b60405190151581526020015b60405180910390f35b348015610350575f80fd5b5061035961088d565b005b348015610366575f80fd5b5061036f6108b4565b60405190815260200161033c565b348015610388575f80fd5b50610391610917565b60405161033c919061251a565b3480156103a9575f80fd5b506103bd6103b836600461252c565b6109a7565b6040516001600160a01b03909116815260200161033c565b6103596103e336600461255e565b6109e9565b3480156103f3575f80fd5b50610359610a87565b348015610407575f80fd5b506001545f540361036f565b34801561041e575f80fd5b5061036f610aab565b610359610435366004612586565b610b0e565b348015610445575f80fd5b50610359610c9e565b348015610459575f80fd5b5061035961046836600461252c565b610d4a565b348015610478575f80fd5b50610359610487366004612646565b610ddb565b348015610497575f80fd5b506103596104a636600461269a565b610e16565b3480156104b6575f80fd5b506104ca6104c53660046126b3565b610e3f565b604080516001600160a01b03909316835260208301919091520161033c565b3480156104f4575f80fd5b50609661036f565b348015610507575f80fd5b5060105461036f565b34801561051b575f80fd5b5061035961052a3660046126d3565b610eeb565b61035961053d366004612586565b610f5d565b34801561054d575f80fd5b5060115461036f565b348015610561575f80fd5b50601354600160301b900460ff16610330565b34801561057f575f80fd5b506103bd61058e36600461252c565b610f77565b34801561059e575f80fd5b50611e6161036f565b6103596105b5366004612780565b610f81565b3480156105c5575f80fd5b5061036f6105d43660046127c8565b6111e8565b6103596105e7366004612780565b611235565b3480156105f7575f80fd5b506103596113c7565b34801561060b575f80fd5b5061035961061a36600461252c565b6113da565b34801561062a575f80fd5b5061035961063936600461252c565b6113e7565b348015610649575f80fd5b506103bd61065836600461252c565b6113f4565b348015610668575f80fd5b506008546001600160a01b03166103bd565b348015610685575f80fd5b506103596106943660046127e1565b6113fe565b3480156106a4575f80fd5b50610391611438565b3480156106b8575f80fd5b5060125461036f565b3480156106cc575f80fd5b506103596106db3660046126d3565b611447565b6103596106ee36600461252c565b6114b3565b3480156106fe575f80fd5b5061035961070d366004612821565b6115f4565b34801561071d575f80fd5b5061033061165f565b610359610734366004612852565b611685565b610359610747366004612891565b611865565b348015610757575f80fd5b5061039161076636600461252c565b6118a9565b348015610776575f80fd5b50601354600160281b900460ff1660405161033c919061291c565b34801561079c575f80fd5b506107a561194a565b60405160ff909116815260200161033c565b3480156107c2575f80fd5b506103596119be565b3480156107d6575f80fd5b506103306107e5366004612942565b6119e1565b3480156107f5575f80fd5b5061035961080436600461252c565b611a0e565b348015610814575f80fd5b506103596108233660046127c8565b611a3d565b348015610833575f80fd5b5061035961084236600461252c565b611a7c565b61035961085536600461252c565b611aab565b348015610865575f80fd5b50600f5461036f565b5f61087882611b8e565b80610887575061088782611bdb565b92915050565b610895611c0f565b601380546001919065ff00000000001916600160281b835b0217905550565b5f80611e616108c56001545f540390565b6108d19061271061297e565b6108db91906129a9565b9050611d4c81101580156108f157506123278111155b156108fe57602891505090565b612328811061090f57601e91505090565b603291505090565b606060028054610926906129bc565b80601f0160208091040260200160405190810160405280929190818152602001828054610952906129bc565b801561099d5780601f106109745761010080835404028352916020019161099d565b820191905f5260205f20905b81548152906001019060200180831161098057829003601f168201915b5050505050905090565b5f6109b182611c3c565b6109ce576040516333d1c03960e21b815260040160405180910390fd5b505f908152600660205260409020546001600160a01b031690565b5f6109f382610f77565b9050336001600160a01b03821614610a2c57610a0f81336119e1565b610a2c576040516367d9dca160e11b815260040160405180910390fd5b5f8281526006602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610a8f611c0f565b601380546002919065ff00000000001916600160281b836108ad565b5f80611e61610abc6001545f540390565b610ac89061271061297e565b610ad291906129a9565b9050611d4c8110158015610ae857506123278111155b15610af557603c91505090565b6123288110610b0657603291505090565b604691505090565b5f610b1882611c61565b9050836001600160a01b0316816001600160a01b031614610b4b5760405162a1148160e81b815260040160405180910390fd5b5f8281526006602052604090208054338082146001600160a01b03881690911417610b9757610b7a86336119e1565b610b9757604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b038516610bbe57604051633a954ecd60e21b815260040160405180910390fd5b8015610bc8575f82555b6001600160a01b038681165f9081526005602052604080822080545f19019055918716808252919020805460010190554260a01b17600160e11b175f85815260046020526040812091909155600160e11b84169003610c5457600184015f818152600460205260408120549003610c52575f548114610c52575f8181526004602052604090208490555b505b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b505050505050565b610ca6611c0f565b475f03610cc6576040516312c002cf60e11b815260040160405180910390fd5b5f610cd96008546001600160a01b031690565b6001600160a01b0316476040515f6040518083038185875af1925050503d805f8114610d20576040519150601f19603f3d011682016040523d82523d5f602084013e610d25565b606091505b5050905080610d475760405163a4a6037f60e01b815260040160405180910390fd5b50565b8033610d5582610f77565b6001600160a01b031614610d7c5760405163074af00f60e31b815260040160405180910390fd5b5f8281526016602052604081205460ff166001811115610d9e57610d9e612908565b14610da9575f610dac565b60015b5f838152601660205260409020805460ff191660018381811115610dd257610dd2612908565b02179055505050565b610de3611c0f565b8080515f03610e05576040516314a565f360e01b815260040160405180910390fd5b600e610e118382612a3f565b505050565b610e1e611c0f565b60138054911515600160301b0266ff00000000000019909216919091179055565b5f828152600a602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610eb35750604080518082019091526009546001600160a01b0381168252600160a01b90046001600160601b031660208201525b60208101515f9061271090610ed1906001600160601b03168761297e565b610edb91906129a9565b91519350909150505b9250929050565b610ef3611c0f565b81818080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920182905250845190039250610f4a915050576040516314a565f360e01b815260040160405180910390fd5b600c610f57838583612afb565b50505050565b610e1183838360405180602001604052805f815250611865565b5f61088782611c61565b5f601354600160281b900460ff166002811115610fa057610fa0612908565b03610fbe57604051631e82594960e21b815260040160405180910390fd5b6001601354600160281b900460ff166002811115610fde57610fde612908565b14610ffc5760405163d88be7df60e01b815260040160405180910390fd5b60135483906103e89061101b908390640100000000900460ff16612bb5565b111561103a576040516365264a7f60e11b815260040160405180910390fd5b601354335f90815260186020526040902054859160ff61010090910481169161106591849116612bb5565b11156110845760405163e48a8d6760e01b815260040160405180910390fd5b601354859062010000900460ff168111156110b25760405163422c9d9f60e11b815260040160405180910390fd5b6110bd858533611cc2565b6110da576040516364b6a9c960e01b815260040160405180910390fd5b856012546110e8919061297e565b34101561110857604051637470432d60e01b815260040160405180910390fd5b5f611114876001611d41565b905060ff81161561119d5780601360048282829054906101000a900460ff1661113d9190612bc8565b82546101009290920a60ff818102199093169183160217909155335f90815260186020526040812080548b9450909261117891859116612bc8565b92506101000a81548160ff021916908360ff16021790555061119d338260ff16611dbf565b604080513381526020810189905260ff83168183015290517f3a8a89b59a31c39a36febecb987e0657ab7b7c73b60ebacb44dcb9886c2d5c8a9181900360600190a150505050505050565b5f6001600160a01b038216611210576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b03165f9081526005602052604090205467ffffffffffffffff1690565b5f601354600160281b900460ff16600281111561125457611254612908565b0361127257604051631e82594960e21b815260040160405180910390fd5b6001601354600160281b900460ff16600281111561129257611292612908565b146112b05760405163d88be7df60e01b815260040160405180910390fd5b60135483906103e8906112cf908390640100000000900460ff16612bb5565b11156112ee576040516365264a7f60e11b815260040160405180910390fd5b601354335f90815260186020526040902054859160ff61010090910481169161131991849116612bb5565b11156113385760405163e48a8d6760e01b815260040160405180910390fd5b601354859062010000900460ff168111156113665760405163422c9d9f60e11b815260040160405180910390fd5b611371858533611cc2565b61138e576040516364b6a9c960e01b815260040160405180910390fd5b8560105461139c919061297e565b3410156113bc57604051637470432d60e01b815260040160405180910390fd5b5f611114875f611d41565b6113cf611c0f565b6113d85f611eb7565b565b6113e2611c0f565b601455565b6113ef611c0f565b601555565b5f61088782610f77565b611406611c0f565b816001600160a01b03811661142e57604051634e22aed760e01b815260040160405180910390fd5b610e118383611f08565b606060038054610926906129bc565b61144f611c0f565b81818080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052508451900392506114a6915050576040516314a565f360e01b815260040160405180910390fd5b600d610f57838583612afb565b5f601354600160281b900460ff1660028111156114d2576114d2612908565b036114f057604051631e82594960e21b815260040160405180910390fd5b6002601354600160281b900460ff16600281111561151057611510612908565b1461152e5760405163c7aac1b760e01b815260040160405180910390fd5b601354819062010000900460ff1681111561155c5760405163422c9d9f60e11b815260040160405180910390fd5b81600f5461156a919061297e565b34101561158a57604051637470432d60e01b815260040160405180910390fd5b5f611595835f611faa565b905060ff8116156115ad576115ad338260ff16611dbf565b604080513381526020810185905260ff83168183015290517f3a8a89b59a31c39a36febecb987e0657ab7b7c73b60ebacb44dcb9886c2d5c8a9181900360600190a1505050565b335f8181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b5f80601354600160281b900460ff16600281111561167f5761167f612908565b14905090565b5f601354600160281b900460ff1660028111156116a4576116a4612908565b036116c257604051631e82594960e21b815260040160405180910390fd5b6001601354600160281b900460ff1660028111156116e2576116e2612908565b146117005760405163d88be7df60e01b815260040160405180910390fd5b60135460969061171b906301000000900460ff166001612bc8565b60ff16111561173d57604051636c08431160e01b815260040160405180910390fd5b601354335f9081526017602052604090205460ff9182169161176191166001612bc8565b60ff161115611783576040516382c774b760e01b815260040160405180910390fd5b61178e828233612019565b6117ab576040516364b6a9c960e01b815260040160405180910390fd5b601380546301000000900460ff169060036117c583612be1565b82546101009290920a60ff818102199093169183160217909155335f908152601760205260408120805490921692506117fd83612be1565b91906101000a81548160ff021916908360ff16021790555050611821336001611dbf565b604080513381526001602082018190528183015290517f3a8a89b59a31c39a36febecb987e0657ab7b7c73b60ebacb44dcb9886c2d5c8a9181900360600190a15050565b611870848484610b0e565b6001600160a01b0383163b15610f575761188c84848484612079565b610f57576040516368d2bf6b60e11b815260040160405180910390fd5b60606118b482611c3c565b6118d1576040516311ee148d60e01b815260040160405180910390fd5b5f6118db83612160565b90505f8151116118f95760405180602001604052805f815250611943565b8061190384612249565b60405180604001604052806005815260200164173539b7b760d91b81525060405160200161193393929190612bff565b6040516020818303038152906040525b9392505050565b5f6001601354600160281b900460ff16600281111561196b5761196b612908565b0361197f5750601354610100900460ff1690565b6002601354600160281b900460ff16600281111561199f5761199f612908565b036119b4575060135462010000900460ff1690565b5060135460ff1690565b6119c6611c0f565b601380545f919065ff00000000001916600160281b836108ad565b6001600160a01b039182165f90815260076020908152604080832093909416825291909152205460ff1690565b611a16611c0f565b80805f03611a37576040516301fb565360e71b815260040160405180910390fd5b50601155565b611a45611c0f565b6001600160a01b038116611a7357604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b610d4781611eb7565b611a84611c0f565b80805f03611aa5576040516301fb565360e71b815260040160405180910390fd5b50600f55565b5f601354600160281b900460ff166002811115611aca57611aca612908565b03611ae857604051631e82594960e21b815260040160405180910390fd5b6002601354600160281b900460ff166002811115611b0857611b08612908565b14611b265760405163c7aac1b760e01b815260040160405180910390fd5b601354819062010000900460ff16811115611b545760405163422c9d9f60e11b815260040160405180910390fd5b81601154611b62919061297e565b341015611b8257604051637470432d60e01b815260040160405180910390fd5b5f611595836001611faa565b5f6301ffc9a760e01b6001600160e01b031983161480611bbe57506380ac58cd60e01b6001600160e01b03198316145b806108875750506001600160e01b031916635b5e139f60e01b1490565b5f6001600160e01b0319821663152a902d60e11b148061088757506301ffc9a760e01b6001600160e01b0319831614610887565b6008546001600160a01b031633146113d85760405163118cdaa760e01b8152336004820152602401611a6a565b5f8054821080156108875750505f90815260046020526040902054600160e01b161590565b5f815f54811015611ca9575f8181526004602052604081205490600160e01b82169003611ca7575b805f0361194357505f19015f81815260046020526040902054611c89565b505b604051636f96cda160e11b815260040160405180910390fd5b5f611d398484808060200260200160405190810160405280939291908181526020018383602002808284375f92019190915250506015546040516bffffffffffffffffffffffff19606089901b16602082015290925060340190505b604051602081830303815290604052805190602001206122d9565b949350505050565b5f808080846001811115611d5757611d57612908565b14611d6957611d646108b4565b611d71565b611d71610aab565b90505f5b85811015611db5575f611d956064611d908462015180612bb5565b6122ee565b9050828111611dac5783611da881612be1565b9450505b50600101611d75565b5090949350505050565b5f805490829003611de35760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b0383165f8181526005602090815260408083208054680100000000000000018802019055848352600490915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b818114611e8f5780835f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4600101611e59565b50815f03611eaf57604051622e076360e81b815260040160405180910390fd5b5f5550505050565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6127106001600160601b038216811015611f4757604051636f483d0960e01b81526001600160601b038316600482015260248101829052604401611a6a565b6001600160a01b038316611f7057604051635b6cc80560e11b81525f6004820152602401611a6a565b50604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600955565b5f808080846001811115611fc057611fc0612908565b14611fd257611fcd6108b4565b611fda565b611fda610aab565b90505f5b85811015611db5575f611ff96064611d908462015180612bb5565b9050828111612010578361200c81612be1565b9450505b50600101611fde565b5f611d398484808060200260200160405190810160405280939291908181526020018383602002808284375f92019190915250506014546040516bffffffffffffffffffffffff19606089901b1660208201529092506034019050611d1e565b604051630a85bd0160e11b81525f906001600160a01b0385169063150b7a02906120ad903390899088908890600401612c41565b6020604051808303815f875af19250505080156120e7575060408051601f3d908101601f191682019092526120e491810190612c7d565b60015b612143573d808015612114576040519150601f19603f3d011682016040523d82523d5f602084013e612119565b606091505b5080515f0361213b576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b5f8181526016602052604090205460135460609160ff90811691600160301b90041661221757600e8054612193906129bc565b80601f01602080910402602001604051908101604052809291908181526020018280546121bf906129bc565b801561220a5780601f106121e15761010080835404028352916020019161220a565b820191905f5260205f20905b8154815290600101906020018083116121ed57829003601f168201915b5050505050915050919050565b5f81600181111561222a5761222a612908565b0361223c57600c8054612193906129bc565b600d8054612193906129bc565b60605f61225583612358565b60010190505f8167ffffffffffffffff811115612274576122746125bf565b6040519080825280601f01601f19166020018201604052801561229e576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846122a857509392505050565b5f826122e5858461242f565b14949350505050565b600b80545f91826122fe83612c98565b9091555083905061230f8342612bb5565b600b5460408051602081019390935244908301526060820152608001604051602081830303815290604052805190602001205f1c61234d9190612cb0565b611943906001612bb5565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106123965772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106123c2576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106123e057662386f26fc10000830492506010015b6305f5e10083106123f8576305f5e100830492506008015b612710831061240c57612710830492506004015b6064831061241e576064830492506002015b600a83106108875760010192915050565b5f81815b84518110156124695761245f8286838151811061245257612452612cc3565b6020026020010151612471565b9150600101612433565b509392505050565b5f81831061248b575f828152602084905260409020611943565b5f838152602083905260409020611943565b6001600160e01b031981168114610d47575f80fd5b5f602082840312156124c2575f80fd5b81356119438161249d565b5f5b838110156124e75781810151838201526020016124cf565b50505f910152565b5f81518084526125068160208601602086016124cd565b601f01601f19169290920160200192915050565b602081525f61194360208301846124ef565b5f6020828403121561253c575f80fd5b5035919050565b80356001600160a01b0381168114612559575f80fd5b919050565b5f806040838503121561256f575f80fd5b61257883612543565b946020939093013593505050565b5f805f60608486031215612598575f80fd5b6125a184612543565b92506125af60208501612543565b9150604084013590509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f67ffffffffffffffff808411156125ed576125ed6125bf565b604051601f8501601f19908116603f01168101908282118183101715612615576126156125bf565b8160405280935085815286868601111561262d575f80fd5b858560208301375f602087830101525050509392505050565b5f60208284031215612656575f80fd5b813567ffffffffffffffff81111561266c575f80fd5b8201601f8101841361267c575f80fd5b611d39848235602084016125d3565b80358015158114612559575f80fd5b5f602082840312156126aa575f80fd5b6119438261268b565b5f80604083850312156126c4575f80fd5b50508035926020909101359150565b5f80602083850312156126e4575f80fd5b823567ffffffffffffffff808211156126fb575f80fd5b818501915085601f83011261270e575f80fd5b81358181111561271c575f80fd5b86602082850101111561272d575f80fd5b60209290920196919550909350505050565b5f8083601f84011261274f575f80fd5b50813567ffffffffffffffff811115612766575f80fd5b6020830191508360208260051b8501011115610ee4575f80fd5b5f805f60408486031215612792575f80fd5b83359250602084013567ffffffffffffffff8111156127af575f80fd5b6127bb8682870161273f565b9497909650939450505050565b5f602082840312156127d8575f80fd5b61194382612543565b5f80604083850312156127f2575f80fd5b6127fb83612543565b915060208301356001600160601b0381168114612816575f80fd5b809150509250929050565b5f8060408385031215612832575f80fd5b61283b83612543565b91506128496020840161268b565b90509250929050565b5f8060208385031215612863575f80fd5b823567ffffffffffffffff811115612879575f80fd5b6128858582860161273f565b90969095509350505050565b5f805f80608085870312156128a4575f80fd5b6128ad85612543565b93506128bb60208601612543565b925060408501359150606085013567ffffffffffffffff8111156128dd575f80fd5b8501601f810187136128ed575f80fd5b6128fc878235602084016125d3565b91505092959194509250565b634e487b7160e01b5f52602160045260245ffd5b602081016003831061293c57634e487b7160e01b5f52602160045260245ffd5b91905290565b5f8060408385031215612953575f80fd5b61295c83612543565b915061284960208401612543565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176108875761088761296a565b634e487b7160e01b5f52601260045260245ffd5b5f826129b7576129b7612995565b500490565b600181811c908216806129d057607f821691505b6020821081036129ee57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115610e1157805f5260205f20601f840160051c81016020851015612a195750805b601f840160051c820191505b81811015612a38575f8155600101612a25565b5050505050565b815167ffffffffffffffff811115612a5957612a596125bf565b612a6d81612a6784546129bc565b846129f4565b602080601f831160018114612aa0575f8415612a895750858301515b5f19600386901b1c1916600185901b178555610c96565b5f85815260208120601f198616915b82811015612ace57888601518255948401946001909101908401612aaf565b5085821015612aeb57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b67ffffffffffffffff831115612b1357612b136125bf565b612b2783612b2183546129bc565b836129f4565b5f601f841160018114612b58575f8515612b415750838201355b5f19600387901b1c1916600186901b178355612a38565b5f83815260208120601f198716915b82811015612b875786850135825560209485019460019092019101612b67565b5086821015612ba3575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b808201808211156108875761088761296a565b60ff81811683821601908111156108875761088761296a565b5f60ff821660ff8103612bf657612bf661296a565b60010192915050565b5f8451612c108184602089016124cd565b845190830190612c248183602089016124cd565b8451910190612c378183602088016124cd565b0195945050505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190525f90612c73908301846124ef565b9695505050505050565b5f60208284031215612c8d575f80fd5b81516119438161249d565b5f60018201612ca957612ca961296a565b5060010190565b5f82612cbe57612cbe612995565b500690565b634e487b7160e01b5f52603260045260245ffdfea264697066735822122083b53e511b958f184a3c37ba355e8927dd77d92e102a9452092a14719879341164736f6c63430008170033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000039d6a3647acdb9cd25f0d0eb93e03341f288ba1200000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000128cd513dc57d8e5ceeb098e584545fb4c340ee000000000000000000000000000000000000000000000000000000000000005968747470733a2f2f6261667962656961373562703370787332676d6c776675767762707277377a716f666475636272716e666c78633565736363746766617833346f712e697066732e6e667473746f726167652e6c696e6b2f00000000000000

-----Decoded View---------------
Arg [0] : _royaltyAddress (address): 0x39d6A3647aCDb9cD25f0d0Eb93E03341F288ba12
Arg [1] : _royaltyBips (uint96): 500
Arg [2] : _unRevealedUri (string): https://bafybeia75bp3pxs2gmlwfuvwbprw7zqofducbrqnflxc5escctgfax34oq.ipfs.nftstorage.link/
Arg [3] : _admin (address): 0x0128Cd513dc57d8E5cEeB098e584545fB4C340eE

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 00000000000000000000000039d6a3647acdb9cd25f0d0eb93e03341f288ba12
Arg [1] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 0000000000000000000000000128cd513dc57d8e5ceeb098e584545fb4c340ee
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000059
Arg [5] : 68747470733a2f2f6261667962656961373562703370787332676d6c77667576
Arg [6] : 7762707277377a716f666475636272716e666c78633565736363746766617833
Arg [7] : 346f712e697066732e6e667473746f726167652e6c696e6b2f00000000000000


Deployed Bytecode Sourcemap

96877:16470:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;112404:215;;;;;;;;;;-1:-1:-1;112404:215:0;;;;;:::i;:::-;;:::i;:::-;;;565:14:1;;558:22;540:41;;528:2;513:18;112404:215:0;;;;;;;;107641:97;;;;;;;;;;;;;:::i;:::-;;105242:334;;;;;;;;;;;;;:::i;:::-;;;738:25:1;;;726:2;711:18;105242:334:0;592:177:1;23498:100:0;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;29989:218::-;;;;;;;;;;-1:-1:-1;29989:218:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1879:32:1;;;1861:51;;1849:2;1834:18;29989:218:0;1715:203:1;29422:408:0;;;;;;:::i;:::-;;:::i;107428:97::-;;;;;;;;;;;;;:::i;19249:323::-;;;;;;;;;;-1:-1:-1;19523:12:0;;19310:7;19507:13;:28;19249:323;;104900:334;;;;;;;;;;;;;:::i;33628:2825::-;;;;;;:::i;:::-;;:::i;113030:314::-;;;;;;;;;;;;;:::i;108442:182::-;;;;;;;;;;-1:-1:-1;108442:182:0;;;;;:::i;:::-;;:::i;107839:152::-;;;;;;;;;;-1:-1:-1;107839:152:0;;;;;:::i;:::-;;:::i;107746:85::-;;;;;;;;;;-1:-1:-1;107746:85:0;;;;;:::i;:::-;;:::i;60320:429::-;;;;;;;;;;-1:-1:-1;60320:429:0;;;;;:::i;:::-;;:::i;:::-;;;;-1:-1:-1;;;;;4713:32:1;;;4695:51;;4777:2;4762:18;;4755:34;;;;4668:18;60320:429:0;4521:274:1;102430:98:0;;;;;;;;;;-1:-1:-1;98115:3:0;102430:98;;102746:94;;;;;;;;;;-1:-1:-1;102819:13:0;;102746:94;;107999:162;;;;;;;;;;-1:-1:-1;107999:162:0;;;;;:::i;:::-;;:::i;36549:193::-;;;;;;:::i;:::-;;:::i;102848:110::-;;;;;;;;;;-1:-1:-1;102929:21:0;;102848:110;;103473:85;;;;;;;;;;-1:-1:-1;103542:8:0;;-1:-1:-1;;;103542:8:0;;;;103473:85;;24891:152;;;;;;;;;;-1:-1:-1;24891:152:0;;;;;:::i;:::-;;:::i;102337:85::-;;;;;;;;;;-1:-1:-1;98063:4:0;102337:85;;111077:794;;;;;;:::i;:::-;;:::i;20433:233::-;;;;;;;;;;-1:-1:-1;20433:233:0;;;;;:::i;:::-;;:::i;110293:776::-;;;;;;:::i;:::-;;:::i;66344:103::-;;;;;;;;;;;;;:::i;108849:206::-;;;;;;;;;;-1:-1:-1;108849:206:0;;;;;:::i;:::-;;:::i;109063:211::-;;;;;;;;;;-1:-1:-1;109063:211:0;;;;;:::i;:::-;;:::i;104443:109::-;;;;;;;;;;-1:-1:-1;104443:109:0;;;;;:::i;:::-;;:::i;65669:87::-;;;;;;;;;;-1:-1:-1;65742:6:0;;-1:-1:-1;;;;;65742:6:0;65669:87;;107243:177;;;;;;;;;;-1:-1:-1;107243:177:0;;;;;:::i;:::-;;:::i;23674:104::-;;;;;;;;;;;;;:::i;102966:115::-;;;;;;;;;;-1:-1:-1;103049:24:0;;102966:115;;108632:209;;;;;;;;;;-1:-1:-1;108632:209:0;;;;;:::i;:::-;;:::i;109449:405::-;;;;;;:::i;:::-;;:::i;30547:234::-;;;;;;;;;;-1:-1:-1;30547:234:0;;;;;:::i;:::-;;:::i;103566:106::-;;;;;;;;;;;;;:::i;111879:348::-;;;;;;:::i;:::-;;:::i;37340:407::-;;;;;;:::i;:::-;;:::i;104025:410::-;;;;;;;;;;-1:-1:-1;104025:410:0;;;;;:::i;:::-;;:::i;103089:96::-;;;;;;;;;;-1:-1:-1;103167:10:0;;-1:-1:-1;;;103167:10:0;;;;103089:96;;;;;;:::i;103193:272::-;;;;;;;;;;;;;:::i;:::-;;;9051:4:1;9039:17;;;9021:36;;9009:2;8994:18;103193:272:0;8879:184:1;107533:100:0;;;;;;;;;;;;;:::i;30938:164::-;;;;;;;;;;-1:-1:-1;30938:164:0;;;;;:::i;:::-;;:::i;108295:139::-;;;;;;;;;;-1:-1:-1;108295:139:0;;;;;:::i;:::-;;:::i;66602:220::-;;;;;;;;;;-1:-1:-1;66602:220:0;;;;;:::i;:::-;;:::i;108169:118::-;;;;;;;;;;-1:-1:-1;108169:118:0;;;;;:::i;:::-;;:::i;109862:423::-;;;;;;:::i;:::-;;:::i;102649:89::-;;;;;;;;;;-1:-1:-1;102720:10:0;;102649:89;;112404:215;112507:4;112531:38;112557:11;112531:25;:38::i;:::-;:80;;;;112573:38;112599:11;112573:25;:38::i;:::-;112524:87;112404:215;-1:-1:-1;;112404:215:0:o;107641:97::-;65555:13;:11;:13::i;:::-;107704:10:::1;:26:::0;;107717:13:::1;::::0;107704:10;-1:-1:-1;;107704:26:0::1;-1:-1:-1::0;;;107717:13:0;107704:26:::1;;;;;;107641:97::o:0;105242:334::-;105295:7;105315:21;98063:4;105340:13;19523:12;;19310:7;19507:13;:28;;19249:323;105340:13;:21;;105356:5;105340:21;:::i;:::-;105339:32;;;;:::i;:::-;105315:56;;105405:4;105388:13;:21;;:46;;;;;105430:4;105413:13;:21;;105388:46;105384:88;;;105458:2;105451:9;;;105242:334;:::o;105384:88::-;105505:4;105488:13;:21;105484:63;;105533:2;105526:9;;;105242:334;:::o;105484:63::-;105566:2;105559:9;;;105242:334;:::o;23498:100::-;23552:13;23585:5;23578:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23498:100;:::o;29989:218::-;30065:7;30090:16;30098:7;30090;:16::i;:::-;30085:64;;30115:34;;-1:-1:-1;;;30115:34:0;;;;;;;;;;;30085:64;-1:-1:-1;30169:24:0;;;;:15;:24;;;;;:30;-1:-1:-1;;;;;30169:30:0;;29989:218::o;29422:408::-;29511:13;29527:16;29535:7;29527;:16::i;:::-;29511:32;-1:-1:-1;53755:10:0;-1:-1:-1;;;;;29560:28:0;;;29556:175;;29608:44;29625:5;53755:10;30938:164;:::i;29608:44::-;29603:128;;29680:35;;-1:-1:-1;;;29680:35:0;;;;;;;;;;;29603:128;29743:24;;;;:15;:24;;;;;;:35;;-1:-1:-1;;;;;;29743:35:0;-1:-1:-1;;;;;29743:35:0;;;;;;;;;29794:28;;29743:24;;29794:28;;;;;;;29500:330;29422:408;;:::o;107428:97::-;65555:13;:11;:13::i;:::-;107489:10:::1;:28:::0;;107502:15:::1;::::0;107489:10;-1:-1:-1;;107489:28:0::1;-1:-1:-1::0;;;107502:15:0;107489:28:::1;::::0;104900:334;104953:7;104973:21;98063:4;104998:13;19523:12;;19310:7;19507:13;:28;;19249:323;104998:13;:21;;105014:5;104998:21;:::i;:::-;104997:32;;;;:::i;:::-;104973:56;;105063:4;105046:13;:21;;:46;;;;;105088:4;105071:13;:21;;105046:46;105042:88;;;105116:2;105109:9;;;104900:334;:::o;105042:88::-;105163:4;105146:13;:21;105142:63;;105191:2;105184:9;;;104900:334;:::o;105142:63::-;105224:2;105217:9;;;104900:334;:::o;33628:2825::-;33770:27;33800;33819:7;33800:18;:27::i;:::-;33770:57;;33885:4;-1:-1:-1;;;;;33844:45:0;33860:19;-1:-1:-1;;;;;33844:45:0;;33840:86;;33898:28;;-1:-1:-1;;;33898:28:0;;;;;;;;;;;33840:86;33940:27;32736:24;;;:15;:24;;;;;32964:26;;53755:10;32361:30;;;-1:-1:-1;;;;;32054:28:0;;32339:20;;;32336:56;34126:180;;34219:43;34236:4;53755:10;30938:164;:::i;34219:43::-;34214:92;;34271:35;;-1:-1:-1;;;34271:35:0;;;;;;;;;;;34214:92;-1:-1:-1;;;;;34323:16:0;;34319:52;;34348:23;;-1:-1:-1;;;34348:23:0;;;;;;;;;;;34319:52;34520:15;34517:160;;;34660:1;34639:19;34632:30;34517:160;-1:-1:-1;;;;;35057:24:0;;;;;;;:18;:24;;;;;;35055:26;;-1:-1:-1;;35055:26:0;;;35126:22;;;;;;;;;35124:24;;-1:-1:-1;35124:24:0;;;28280:11;28255:23;28251:41;28238:63;-1:-1:-1;;;28238:63:0;35419:26;;;;:17;:26;;;;;:175;;;;-1:-1:-1;;;35714:47:0;;:52;;35710:627;;35819:1;35809:11;;35787:19;35942:30;;;:17;:30;;;;;;:35;;35938:384;;36080:13;;36065:11;:28;36061:242;;36227:30;;;;:17;:30;;;;;:52;;;36061:242;35768:569;35710:627;36384:7;36380:2;-1:-1:-1;;;;;36365:27:0;36374:4;-1:-1:-1;;;;;36365:27:0;;;;;;;;;;;36403:42;33759:2694;;;33628:2825;;;:::o;113030:314::-;65555:13;:11;:13::i;:::-;113089:21:::1;113114:1;113089:26:::0;113085:94:::1;;113139:28;;-1:-1:-1::0;;;113139:28:0::1;;;;;;;;;;;113085:94;113190:12;113207:7;65742:6:::0;;-1:-1:-1;;;;;65742:6:0;;65669:87;113207:7:::1;-1:-1:-1::0;;;;;113207:12:0::1;113227:21;113207:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;113189:64;;;113269:7;113264:73;;113300:25;;-1:-1:-1::0;;;113300:25:0::1;;;;;;;;;;;113264:73;113074:270;113030:314::o:0;108442:182::-;108507:7;101144:10;101124:16;108507:7;101124;:16::i;:::-;-1:-1:-1;;;;;101124:30:0;;101120:95;;101178:25;;-1:-1:-1;;;101178:25:0;;;;;;;;;;;101120:95;108568:14:::1;108547:17:::0;;;:8:::1;:17;::::0;;;;;::::1;;::::0;:35;::::1;;;;;;:::i;:::-;;:69;;108602:14;108547:69;;;108585:14;108547:69;108527:17;::::0;;;:8:::1;:17;::::0;;;;:89;;-1:-1:-1;;108527:89:0::1;::::0;;;;::::1;;;;;;:::i;:::-;;;;;;108442:182:::0;;:::o;107839:152::-;65555:13;:11;:13::i;:::-;107926:14:::1;100194:4;100188:18;100210:1;100188:23:::0;100184:80:::1;;100235:17;;-1:-1:-1::0;;;100235:17:0::1;;;;;;;;;;;100184:80;107953:13:::2;:30;107969:14:::0;107953:13;:30:::2;:::i;:::-;;65579:1:::1;107839:152:::0;:::o;107746:85::-;65555:13;:11;:13::i;:::-;107807:8:::1;:16:::0;;;::::1;;-1:-1:-1::0;;;107807:16:0::1;-1:-1:-1::0;;107807:16:0;;::::1;::::0;;;::::1;::::0;;107746:85::o;60320:429::-;60406:7;60464:26;;;:17;:26;;;;;;;;60435:55;;;;;;;;;-1:-1:-1;;;;;60435:55:0;;;;;-1:-1:-1;;;60435:55:0;;;-1:-1:-1;;;;;60435:55:0;;;;;;;;60406:7;;60503:92;;-1:-1:-1;60554:29:0;;;;;;;;;60564:19;60554:29;-1:-1:-1;;;;;60554:29:0;;;;-1:-1:-1;;;60554:29:0;;-1:-1:-1;;;;;60554:29:0;;;;;60503:92;60644:23;;;;60607:21;;61115:5;;60632:35;;-1:-1:-1;;;;;60632:35:0;:9;:35;:::i;:::-;60631:57;;;;:::i;:::-;60709:16;;;-1:-1:-1;60607:81:0;;-1:-1:-1;;60320:429:0;;;;;;:::o;107999:162::-;65555:13;:11;:13::i;:::-;108090:16:::1;;100130:153;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;-1:-1:-1;100188:18:0;;:23;;;-1:-1:-1;100184:80:0::1;::::0;-1:-1:-1;;100184:80:0::1;100235:17;;-1:-1:-1::0;;;100235:17:0::1;;;;;;;;;;;100184:80;108119:15:::2;:34;108137:16:::0;;108119:15;:34:::2;:::i;:::-;;65579:1:::1;107999:162:::0;;:::o;36549:193::-;36695:39;36712:4;36718:2;36722:7;36695:39;;;;;;;;;;;;:16;:39::i;24891:152::-;24963:7;25006:27;25025:7;25006:18;:27::i;111077:794::-;100654:17;100640:10;;-1:-1:-1;;;100640:10:0;;;;:31;;;;;;;;:::i;:::-;;100636:90;;100695:19;;-1:-1:-1;;;100695:19:0;;;;;;;;;;;100636:90;100802:13:::1;100788:10;::::0;-1:-1:-1;;;100788:10:0;::::1;;;:27;::::0;::::1;;;;;;:::i;:::-;;100784:96;;100839:29;;-1:-1:-1::0;;;100839:29:0::1;;;;;;;;;;;100784:96;101474:14:::2;::::0;111243:7;;98223:4:::2;::::0;101474:24:::2;::::0;111243:7;;101474:14;;::::2;;;:24;:::i;:::-;:42;101470:112;;;101540:30;;-1:-1:-1::0;;;101540:30:0::2;;;;;;;;;;;101470:112;101878:14:::3;::::0;101854:10:::3;101843:22;::::0;;;:10:::3;:22;::::0;;;;;111278:7;;101878:14:::3;;::::0;;::::3;::::0;::::3;::::0;101843:32:::3;::::0;111278:7;;101843:22:::3;:32;:::i;:::-;:49;101839:120;;;101916:31;;-1:-1:-1::0;;;101916:31:0::3;;;;;;;;;;;101839:120;102062:8:::4;::::0;111321:7;;102062:8;;::::4;;;102052:18:::0;::::4;102048:96;;;102094:38;;-1:-1:-1::0;;;102094:38:0::4;;;;;;;;;;;102048:96;111351:28:::5;111360:6;;111368:10;111351:8;:28::i;:::-;111346:89;;111403:20;;-1:-1:-1::0;;;111403:20:0::5;;;;;;;;;;;111346:89;111488:7;111461:24;;:34;;;;:::i;:::-;111449:9;:46;111445:112;;;111519:26;;-1:-1:-1::0;;;111519:26:0::5;;;;;;;;;;;111445:112;111567:15;111585:40;111601:7;111610:14;111585:15;:40::i;:::-;111567:58:::0;-1:-1:-1;111640:13:0::5;::::0;::::5;::::0;111636:171:::5;;111688:9;111670:14;;:27;;;;;;;;;;;;;;;;:::i;:::-;::::0;;::::5;::::0;;;::::5;;::::0;;::::5;;::::0;;::::5;::::0;;::::5;;;::::0;;;111723:10:::5;-1:-1:-1::0;111712:22:0;;;:10:::5;:22;::::0;;;;:40;;111744:7;;-1:-1:-1;111712:22:0;;:40:::5;::::0;111744:7;;111712:40:::5;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;111767:28;111773:10;111785:9;111767:28;;:5;:28::i;:::-;111822:41;::::0;;111832:10:::5;14346:51:1::0;;14428:2;14413:18;;14406:34;;;14488:4;14476:17;;14456:18;;;14449:45;111822:41:0;;::::5;::::0;;;;14334:2:1;111822:41:0;;::::5;111335:536;101969:1:::4;101594::::3;100890::::2;111077:794:::0;;;:::o;20433:233::-;20505:7;-1:-1:-1;;;;;20529:19:0;;20525:60;;20557:28;;-1:-1:-1;;;20557:28:0;;;;;;;;;;;20525:60;-1:-1:-1;;;;;;20603:25:0;;;;;:18;:25;;;;;;14592:13;20603:55;;20433:233::o;110293:776::-;100654:17;100640:10;;-1:-1:-1;;;100640:10:0;;;;:31;;;;;;;;:::i;:::-;;100636:90;;100695:19;;-1:-1:-1;;;100695:19:0;;;;;;;;;;;100636:90;100802:13:::1;100788:10;::::0;-1:-1:-1;;;100788:10:0;::::1;;;:27;::::0;::::1;;;;;;:::i;:::-;;100784:96;;100839:29;;-1:-1:-1::0;;;100839:29:0::1;;;;;;;;;;;100784:96;101474:14:::2;::::0;110452:7;;98223:4:::2;::::0;101474:24:::2;::::0;110452:7;;101474:14;;::::2;;;:24;:::i;:::-;:42;101470:112;;;101540:30;;-1:-1:-1::0;;;101540:30:0::2;;;;;;;;;;;101470:112;101878:14:::3;::::0;101854:10:::3;101843:22;::::0;;;:10:::3;:22;::::0;;;;;110487:7;;101878:14:::3;;::::0;;::::3;::::0;::::3;::::0;101843:32:::3;::::0;110487:7;;101843:22:::3;:32;:::i;:::-;:49;101839:120;;;101916:31;;-1:-1:-1::0;;;101916:31:0::3;;;;;;;;;;;101839:120;102062:8:::4;::::0;110530:7;;102062:8;;::::4;;;102052:18:::0;::::4;102048:96;;;102094:38;;-1:-1:-1::0;;;102094:38:0::4;;;;;;;;;;;102048:96;110560:28:::5;110569:6;;110577:10;110560:8;:28::i;:::-;110555:89;;110612:20;;-1:-1:-1::0;;;110612:20:0::5;;;;;;;;;;;110555:89;110686:7;110670:13;;:23;;;;:::i;:::-;110658:9;:35;110654:101;;;110717:26;;-1:-1:-1::0;;;110717:26:0::5;;;;;;;;;;;110654:101;110765:15;110783:40;110799:7;110808:14;110783:15;:40::i;66344:103::-:0;65555:13;:11;:13::i;:::-;66409:30:::1;66436:1;66409:18;:30::i;:::-;66344:103::o:0;108849:206::-;65555:13;:11;:13::i;:::-;109023:10:::1;:24:::0;108849:206::o;109063:211::-;65555:13;:11;:13::i;:::-;109239::::1;:27:::0;109063:211::o;104443:109::-;104501:7;104528:16;104536:7;104528;:16::i;107243:177::-;65555:13;:11;:13::i;:::-;107342:9;-1:-1:-1;;;;;100350:22:0;::::1;100346:82;;100396:20;;-1:-1:-1::0;;;100396:20:0::1;;;;;;;;;;;100346:82;107364:48:::2;107383:9;107394:17;107364:18;:48::i;23674:104::-:0;23730:13;23763:7;23756:14;;;;;:::i;108632:209::-;65555:13;:11;:13::i;:::-;108756:19:::1;;100130:153;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;-1:-1:-1;100188:18:0;;:23;;;-1:-1:-1;100184:80:0::1;::::0;-1:-1:-1;;100184:80:0::1;100235:17;;-1:-1:-1::0;;;100235:17:0::1;;;;;;;;;;;100184:80;108793:18:::2;:40;108814:19:::0;;108793:18;:40:::2;:::i;109449:405::-:0;100654:17;100640:10;;-1:-1:-1;;;100640:10:0;;;;:31;;;;;;;;:::i;:::-;;100636:90;;100695:19;;-1:-1:-1;;;100695:19:0;;;;;;;;;;;100636:90;100960:15:::1;100946:10;::::0;-1:-1:-1;;;100946:10:0;::::1;;;:29;::::0;::::1;;;;;;:::i;:::-;;100942:99;;100999:30;;-1:-1:-1::0;;;100999:30:0::1;;;;;;;;;;;100942:99;102062:8:::2;::::0;109547:7;;102062:8;;::::2;;;102052:18:::0;::::2;102048:96;;;102094:38;;-1:-1:-1::0;;;102094:38:0::2;;;;;;;;;;;102048:96;109596:7:::3;109583:10;;:20;;;;:::i;:::-;109571:9;:32;109567:98;;;109627:26;;-1:-1:-1::0;;;109627:26:0::3;;;;;;;;;;;109567:98;109675:15;109693:38;109707:7;109716:14;109693:13;:38::i;:::-;109675:56:::0;-1:-1:-1;109746:13:0::3;::::0;::::3;::::0;109742:47:::3;;109761:28;109767:10;109779:9;109761:28;;:5;:28::i;:::-;109805:41;::::0;;109815:10:::3;14346:51:1::0;;14428:2;14413:18;;14406:34;;;14488:4;14476:17;;14456:18;;;14449:45;109805:41:0;;::::3;::::0;;;;14334:2:1;109805:41:0;;::::3;109556:298;101051:1:::2;109449:405:::0;:::o;30547:234::-;53755:10;30642:39;;;;:18;:39;;;;;;;;-1:-1:-1;;;;;30642:49:0;;;;;;;;;;;;:60;;-1:-1:-1;;30642:60:0;;;;;;;;;;30718:55;;540:41:1;;;30642:49:0;;53755:10;30718:55;;513:18:1;30718:55:0;;;;;;;30547:234;;:::o;103566:106::-;103609:4;;103633:10;;-1:-1:-1;;;103633:10:0;;;;:31;;;;;;;;:::i;:::-;;103626:38;;103566:106;:::o;111879:348::-;100654:17;100640:10;;-1:-1:-1;;;100640:10:0;;;;:31;;;;;;;;:::i;:::-;;100636:90;;100695:19;;-1:-1:-1;;;100695:19:0;;;;;;;;;;;100636:90;100802:13:::1;100788:10;::::0;-1:-1:-1;;;100788:10:0;::::1;;;:27;::::0;::::1;;;;;;:::i;:::-;;100784:96;;100839:29;;-1:-1:-1::0;;;100839:29:0::1;;;;;;;;;;;100784:96;101281:16:::2;::::0;98170:3:::2;::::0;101281:20:::2;::::0;:16;;::::2;;;101300:1;101281:20;:::i;:::-;:40;;;101277:112;;;101345:32;;-1:-1:-1::0;;;101345:32:0::2;;;;;;;;;;;101277:112;101678:11:::3;::::0;101660:10:::3;101678:11;101652:19:::0;;;:7:::3;:19;::::0;;;;;101678:11:::3;::::0;;::::3;::::0;101652:23:::3;::::0;:19:::3;101678:11:::0;101652:23:::3;:::i;:::-;:37;;;101648:110;;;101713:33;;-1:-1:-1::0;;;101713:33:0::3;;;;;;;;;;;101648:110;112003:26:::4;112010:6;;112018:10;112003:6;:26::i;:::-;111998:87;;112053:20;;-1:-1:-1::0;;;112053:20:0::4;;;;;;;;;;;111998:87;112095:16;:18:::0;;;;::::4;;;::::0;:16:::4;:18;::::0;::::4;:::i;:::-;::::0;;::::4;::::0;;;::::4;;::::0;;::::4;;::::0;;::::4;::::0;;::::4;;;::::0;;;112132:10:::4;-1:-1:-1::0;112124:19:0;;;:7:::4;:19;::::0;;;;:21;;;;::::4;::::0;-1:-1:-1;112124:21:0::4;::::0;::::4;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;112156:20;112162:10;112174:1;112156:5;:20::i;:::-;112192:27;::::0;;112202:10:::4;14903:51:1::0;;112214:1:0::4;14985:2:1::0;14970:18;;14963:34;;;15013:18;;;15006:34;112192:27:0;;::::4;::::0;;;;14891:2:1;112192:27:0;;::::4;111879:348:::0;;:::o;37340:407::-;37515:31;37528:4;37534:2;37538:7;37515:12;:31::i;:::-;-1:-1:-1;;;;;37561:14:0;;;:19;37557:183;;37600:56;37631:4;37637:2;37641:7;37650:5;37600:30;:56::i;:::-;37595:145;;37684:40;;-1:-1:-1;;;37684:40:0;;;;;;;;;;;104025:410;104098:13;104129:16;104137:7;104129;:16::i;:::-;104124:82;;104169:25;;-1:-1:-1;;;104169:25:0;;;;;;;;;;;104124:82;104218:29;104250:16;104258:7;104250;:16::i;:::-;104218:48;;104316:1;104290:15;104284:29;:33;:143;;;;;;;;;;;;;;;;;104357:15;104374:18;:7;:16;:18::i;:::-;104394:13;;;;;;;;;;;;;-1:-1:-1;;;104394:13:0;;;104340:68;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;104284:143;104277:150;104025:410;-1:-1:-1;;;104025:410:0:o;103193:272::-;103239:5;103275:13;103261:10;;-1:-1:-1;;;103261:10:0;;;;:27;;;;;;;;:::i;:::-;;103257:81;;-1:-1:-1;103312:14:0;;;;;;;;103193:272::o;103257:81::-;103368:15;103354:10;;-1:-1:-1;;;103354:10:0;;;;:29;;;;;;;;:::i;:::-;;103350:77;;-1:-1:-1;103407:8:0;;;;;;;;103193:272::o;103350:77::-;-1:-1:-1;103446:11:0;;;;;103193:272::o;107533:100::-;65555:13;:11;:13::i;:::-;107595:10:::1;:30:::0;;107608:17:::1;::::0;107595:10;-1:-1:-1;;107595:30:0::1;-1:-1:-1::0;;;107608:17:0;107595:30:::1;::::0;30938:164;-1:-1:-1;;;;;31059:25:0;;;31035:4;31059:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;30938:164::o;108295:139::-;65555:13;:11;:13::i;:::-;108377:6:::1;100510;100520:1;100510:11:::0;100506:69:::1;;100545:18;;-1:-1:-1::0;;;100545:18:0::1;;;;;;;;;;;100506:69;-1:-1:-1::0;108396:21:0::2;:30:::0;108295:139::o;66602:220::-;65555:13;:11;:13::i;:::-;-1:-1:-1;;;;;66687:22:0;::::1;66683:93;;66733:31;::::0;-1:-1:-1;;;66733:31:0;;66761:1:::1;66733:31;::::0;::::1;1861:51:1::0;1834:18;;66733:31:0::1;;;;;;;;66683:93;66786:28;66805:8;66786:18;:28::i;108169:118::-:0;65555:13;:11;:13::i;:::-;108241:6:::1;100510;100520:1;100510:11:::0;100506:69:::1;;100545:18;;-1:-1:-1::0;;;100545:18:0::1;;;;;;;;;;;100506:69;-1:-1:-1::0;108260:10:0::2;:19:::0;108169:118::o;109862:423::-;100654:17;100640:10;;-1:-1:-1;;;100640:10:0;;;;:31;;;;;;;;:::i;:::-;;100636:90;;100695:19;;-1:-1:-1;;;100695:19:0;;;;;;;;;;;100636:90;100960:15:::1;100946:10;::::0;-1:-1:-1;;;100946:10:0;::::1;;;:29;::::0;::::1;;;;;;:::i;:::-;;100942:99;;100999:30;;-1:-1:-1::0;;;100999:30:0::1;;;;;;;;;;;100942:99;102062:8:::2;::::0;109967:7;;102062:8;;::::2;;;102052:18:::0;::::2;102048:96;;;102094:38;;-1:-1:-1::0;;;102094:38:0::2;;;;;;;;;;;102048:96;110027:7:::3;110003:21;;:31;;;;:::i;:::-;109991:9;:43;109987:109;;;110058:26;;-1:-1:-1::0;;;110058:26:0::3;;;;;;;;;;;109987:109;110106:15;110124:38;110138:7;110147:14;110124:13;:38::i;22596:639::-:0;22681:4;-1:-1:-1;;;;;;;;;23005:25:0;;;;:102;;-1:-1:-1;;;;;;;;;;23082:25:0;;;23005:102;:179;;;-1:-1:-1;;;;;;;;23159:25:0;-1:-1:-1;;;23159:25:0;;22596:639::o;60050:215::-;60152:4;-1:-1:-1;;;;;;60176:41:0;;-1:-1:-1;;;60176:41:0;;:81;;-1:-1:-1;;;;;;;;;;58095:40:0;;;60221:36;57995:148;65834:166;65742:6;;-1:-1:-1;;;;;65742:6:0;53755:10;65894:23;65890:103;;65941:40;;-1:-1:-1;;;65941:40:0;;53755:10;65941:40;;;1861:51:1;1834:18;;65941:40:0;1715:203:1;31360:282:0;31425:4;31515:13;;31505:7;:23;31462:153;;;;-1:-1:-1;;31566:26:0;;;;:17;:26;;;;;;-1:-1:-1;;;31566:44:0;:49;;31360:282::o;26046:1275::-;26113:7;26148;26250:13;;26243:4;:20;26239:1015;;;26288:14;26305:23;;;:17;:23;;;;;;;-1:-1:-1;;;26394:24:0;;:29;;26390:845;;27059:113;27066:6;27076:1;27066:11;27059:113;;-1:-1:-1;;;27137:6:0;27119:25;;;;:17;:25;;;;;;27059:113;;26390:845;26265:989;26239:1015;27282:31;;-1:-1:-1;;;27282:31:0;;;;;;;;;;;112826:196;112911:4;112935:79;112954:6;;112935:79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;112962:13:0;;112987:25;;-1:-1:-1;;15908:2:1;15904:15;;;15900:53;112987:25:0;;;15888:66:1;112962:13:0;;-1:-1:-1;15970:12:1;;;-1:-1:-1;112987:25:0;;;;;;;;;;;;;112977:36;;;;;;112935:18;:79::i;:::-;112928:86;112826:196;-1:-1:-1;;;;112826:196:0:o;106615:454::-;106690:5;;;;106756:4;:22;;;;;;;;:::i;:::-;;:74;;106806:24;:22;:24::i;:::-;106756:74;;;106781:22;:20;:22::i;:::-;106734:96;;106846:9;106841:192;106865:7;106861:1;:11;106841:192;;;106894:11;106908:29;106921:3;106926:10;:1;106930:6;106926:10;:::i;:::-;106908:12;:29::i;:::-;106894:43;;106963:11;106956:3;:18;106952:70;;106995:11;;;;:::i;:::-;;;;106952:70;-1:-1:-1;106874:3:0;;106841:192;;;-1:-1:-1;107052:9:0;;106615:454;-1:-1:-1;;;;106615:454:0:o;41009:2966::-;41082:20;41105:13;;;41133;;;41129:44;;41155:18;;-1:-1:-1;;;41155:18:0;;;;;;;;;;;41129:44;-1:-1:-1;;;;;41661:22:0;;;;;;:18;:22;;;;14730:2;41661:22;;;:71;;41699:32;41687:45;;41661:71;;;41975:31;;;:17;:31;;;;;-1:-1:-1;28711:15:0;;28685:24;28681:46;28280:11;28255:23;28251:41;28248:52;28238:63;;41975:173;;42210:23;;;;41975:31;;41661:22;;42975:25;41661:22;;42828:335;43489:1;43475:12;43471:20;43429:346;43530:3;43521:7;43518:16;43429:346;;43748:7;43738:8;43735:1;43708:25;43705:1;43702;43697:59;43583:1;43570:15;43429:346;;;43433:77;43808:8;43820:1;43808:13;43804:45;;43830:19;;-1:-1:-1;;;43830:19:0;;;;;;;;;;;43804:45;43866:13;:19;-1:-1:-1;107953:30:0::2;65579:1:::1;107839:152:::0;:::o;66982:191::-;67075:6;;;-1:-1:-1;;;;;67092:17:0;;;-1:-1:-1;;;;;;67092:17:0;;;;;;;67125:40;;67075:6;;;67092:17;67075:6;;67125:40;;67056:16;;67125:40;67045:128;66982:191;:::o;61399:518::-;61115:5;-1:-1:-1;;;;;61548:26:0;;;-1:-1:-1;61544:176:0;;;61653:55;;-1:-1:-1;;;61653:55:0;;-1:-1:-1;;;;;16184:39:1;;61653:55:0;;;16166:58:1;16240:18;;;16233:34;;;16139:18;;61653:55:0;15993:280:1;61544:176:0;-1:-1:-1;;;;;61734:22:0;;61730:110;;61780:48;;-1:-1:-1;;;61780:48:0;;61825:1;61780:48;;;1861:51:1;1834:18;;61780:48:0;1715:203:1;61730:110:0;-1:-1:-1;61874:35:0;;;;;;;;;-1:-1:-1;;;;;61874:35:0;;;;;;-1:-1:-1;;;;;61874:35:0;;;;;;;;;;-1:-1:-1;;;61852:57:0;;;;:19;:57;61399:518::o;106159:448::-;106232:5;;;;106298:4;:22;;;;;;;;:::i;:::-;;:70;;106346:22;:20;:22::i;:::-;106298:70;;;106323:20;:18;:20::i;:::-;106276:92;;106384:9;106379:192;106403:7;106399:1;:11;106379:192;;;106432:11;106446:29;106459:3;106464:10;:1;106468:6;106464:10;:::i;106446:29::-;106432:43;;106501:11;106494:3;:18;106490:70;;106533:11;;;;:::i;:::-;;;;106490:70;-1:-1:-1;106412:3:0;;106379:192;;112627:191;112710:4;112734:76;112753:6;;112734:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;112761:10:0;;112783:25;;-1:-1:-1;;15908:2:1;15904:15;;;15900:53;112783:25:0;;;15888:66:1;112761:10:0;;-1:-1:-1;15970:12:1;;;-1:-1:-1;112783:25:0;15759:229:1;39831:716:0;40015:88;;-1:-1:-1;;;40015:88:0;;39994:4;;-1:-1:-1;;;;;40015:45:0;;;;;:88;;53755:10;;40082:4;;40088:7;;40097:5;;40015:88;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;40015:88:0;;;;;;;;-1:-1:-1;;40015:88:0;;;;;;;;;;;;:::i;:::-;;;40011:529;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40298:6;:13;40315:1;40298:18;40294:235;;40344:40;;-1:-1:-1;;;40344:40:0;;;;;;;;;;;40294:235;40487:6;40481:13;40472:6;40468:2;40464:15;40457:38;40011:529;-1:-1:-1;;;;;;40174:64:0;-1:-1:-1;;;40174:64:0;;-1:-1:-1;39831:716:0;;;;;;:::o;103680:337::-;103763:21;103787:17;;;:8;:17;;;;;;103820:8;;103737:13;;103787:17;;;;;-1:-1:-1;;;103820:8:0;;;103815:62;;103852:13;103845:20;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;103680:337;;;:::o;103815:62::-;103909:14;103893:12;:30;;;;;;;;:::i;:::-;;103889:85;;103947:15;103940:22;;;;;:::i;103889:85::-;103991:18;103984:25;;;;;:::i;84409:718::-;84465:13;84516:14;84533:17;84544:5;84533:10;:17::i;:::-;84553:1;84533:21;84516:38;;84569:20;84603:6;84592:18;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84592:18:0;-1:-1:-1;84569:41:0;-1:-1:-1;84734:28:0;;;84750:2;84734:28;84791:290;-1:-1:-1;;84823:5:0;-1:-1:-1;;;84960:2:0;84949:14;;84944:32;84823:5;84931:46;85023:2;85014:11;;;-1:-1:-1;85044:21:0;84791:290;85044:21;-1:-1:-1;85102:6:0;84409:718;-1:-1:-1;;;84409:718:0:o;88179:156::-;88270:4;88323;88294:25;88307:5;88314:4;88294:12;:25::i;:::-;:33;;88179:156;-1:-1:-1;;;;88179:156:0:o;105928:223::-;106019:5;:7;;105999;;;106019;;;:::i;:::-;;;;-1:-1:-1;106134:5:0;;-1:-1:-1;106079:24:0;106097:6;106079:15;:24;:::i;:::-;106123:5;;106062:67;;;;;;17351:19:1;;;;106105:16:0;17386:12:1;;;17379:28;17423:12;;;17416:28;17460:12;;106062:67:0;;;;;;;;;;;;106052:78;;;;;;106044:87;;:95;;;;:::i;:::-;:99;;106142:1;106044:99;:::i;79724:948::-;79777:7;;-1:-1:-1;;;79855:17:0;;79851:106;;-1:-1:-1;;;79893:17:0;;;-1:-1:-1;79939:2:0;79929:12;79851:106;79984:8;79975:5;:17;79971:106;;80022:8;80013:17;;;-1:-1:-1;80059:2:0;80049:12;79971:106;80104:8;80095:5;:17;80091:106;;80142:8;80133:17;;;-1:-1:-1;80179:2:0;80169:12;80091:106;80224:7;80215:5;:16;80211:103;;80261:7;80252:16;;;-1:-1:-1;80297:1:0;80287:11;80211:103;80341:7;80332:5;:16;80328:103;;80378:7;80369:16;;;-1:-1:-1;80414:1:0;80404:11;80328:103;80458:7;80449:5;:16;80445:103;;80495:7;80486:16;;;-1:-1:-1;80531:1:0;80521:11;80445:103;80575:7;80566:5;:16;80562:68;;80613:1;80603:11;80658:6;79724:948;-1:-1:-1;;79724:948:0:o;88898:296::-;88981:7;89024:4;88981:7;89039:118;89063:5;:12;89059:1;:16;89039:118;;;89112:33;89122:12;89136:5;89142:1;89136:8;;;;;;;;:::i;:::-;;;;;;;89112:9;:33::i;:::-;89097:48;-1:-1:-1;89077:3:0;;89039:118;;;-1:-1:-1;89174:12:0;88898:296;-1:-1:-1;;;88898:296:0:o;96328:149::-;96391:7;96422:1;96418;:5;:51;;96670:13;96764:15;;;96800:4;96793:15;;;96847:4;96831:21;;96418:51;;;96670:13;96764:15;;;96800:4;96793:15;;;96847:4;96831:21;;96426:20;96602:268;14:131:1;-1:-1:-1;;;;;;88:32:1;;78:43;;68:71;;135:1;132;125:12;150:245;208:6;261:2;249:9;240:7;236:23;232:32;229:52;;;277:1;274;267:12;229:52;316:9;303:23;335:30;359:5;335:30;:::i;774:250::-;859:1;869:113;883:6;880:1;877:13;869:113;;;959:11;;;953:18;940:11;;;933:39;905:2;898:10;869:113;;;-1:-1:-1;;1016:1:1;998:16;;991:27;774:250::o;1029:271::-;1071:3;1109:5;1103:12;1136:6;1131:3;1124:19;1152:76;1221:6;1214:4;1209:3;1205:14;1198:4;1191:5;1187:16;1152:76;:::i;:::-;1282:2;1261:15;-1:-1:-1;;1257:29:1;1248:39;;;;1289:4;1244:50;;1029:271;-1:-1:-1;;1029:271:1:o;1305:220::-;1454:2;1443:9;1436:21;1417:4;1474:45;1515:2;1504:9;1500:18;1492:6;1474:45;:::i;1530:180::-;1589:6;1642:2;1630:9;1621:7;1617:23;1613:32;1610:52;;;1658:1;1655;1648:12;1610:52;-1:-1:-1;1681:23:1;;1530:180;-1:-1:-1;1530:180:1:o;1923:173::-;1991:20;;-1:-1:-1;;;;;2040:31:1;;2030:42;;2020:70;;2086:1;2083;2076:12;2020:70;1923:173;;;:::o;2101:254::-;2169:6;2177;2230:2;2218:9;2209:7;2205:23;2201:32;2198:52;;;2246:1;2243;2236:12;2198:52;2269:29;2288:9;2269:29;:::i;:::-;2259:39;2345:2;2330:18;;;;2317:32;;-1:-1:-1;;;2101:254:1:o;2360:328::-;2437:6;2445;2453;2506:2;2494:9;2485:7;2481:23;2477:32;2474:52;;;2522:1;2519;2512:12;2474:52;2545:29;2564:9;2545:29;:::i;:::-;2535:39;;2593:38;2627:2;2616:9;2612:18;2593:38;:::i;:::-;2583:48;;2678:2;2667:9;2663:18;2650:32;2640:42;;2360:328;;;;;:::o;2693:127::-;2754:10;2749:3;2745:20;2742:1;2735:31;2785:4;2782:1;2775:15;2809:4;2806:1;2799:15;2825:632;2890:5;2920:18;2961:2;2953:6;2950:14;2947:40;;;2967:18;;:::i;:::-;3042:2;3036:9;3010:2;3096:15;;-1:-1:-1;;3092:24:1;;;3118:2;3088:33;3084:42;3072:55;;;3142:18;;;3162:22;;;3139:46;3136:72;;;3188:18;;:::i;:::-;3228:10;3224:2;3217:22;3257:6;3248:15;;3287:6;3279;3272:22;3327:3;3318:6;3313:3;3309:16;3306:25;3303:45;;;3344:1;3341;3334:12;3303:45;3394:6;3389:3;3382:4;3374:6;3370:17;3357:44;3449:1;3442:4;3433:6;3425;3421:19;3417:30;3410:41;;;;2825:632;;;;;:::o;3462:451::-;3531:6;3584:2;3572:9;3563:7;3559:23;3555:32;3552:52;;;3600:1;3597;3590:12;3552:52;3640:9;3627:23;3673:18;3665:6;3662:30;3659:50;;;3705:1;3702;3695:12;3659:50;3728:22;;3781:4;3773:13;;3769:27;-1:-1:-1;3759:55:1;;3810:1;3807;3800:12;3759:55;3833:74;3899:7;3894:2;3881:16;3876:2;3872;3868:11;3833:74;:::i;3918:160::-;3983:20;;4039:13;;4032:21;4022:32;;4012:60;;4068:1;4065;4058:12;4083:180;4139:6;4192:2;4180:9;4171:7;4167:23;4163:32;4160:52;;;4208:1;4205;4198:12;4160:52;4231:26;4247:9;4231:26;:::i;4268:248::-;4336:6;4344;4397:2;4385:9;4376:7;4372:23;4368:32;4365:52;;;4413:1;4410;4403:12;4365:52;-1:-1:-1;;4436:23:1;;;4506:2;4491:18;;;4478:32;;-1:-1:-1;4268:248:1:o;4800:592::-;4871:6;4879;4932:2;4920:9;4911:7;4907:23;4903:32;4900:52;;;4948:1;4945;4938:12;4900:52;4988:9;4975:23;5017:18;5058:2;5050:6;5047:14;5044:34;;;5074:1;5071;5064:12;5044:34;5112:6;5101:9;5097:22;5087:32;;5157:7;5150:4;5146:2;5142:13;5138:27;5128:55;;5179:1;5176;5169:12;5128:55;5219:2;5206:16;5245:2;5237:6;5234:14;5231:34;;;5261:1;5258;5251:12;5231:34;5306:7;5301:2;5292:6;5288:2;5284:15;5280:24;5277:37;5274:57;;;5327:1;5324;5317:12;5274:57;5358:2;5350:11;;;;;5380:6;;-1:-1:-1;4800:592:1;;-1:-1:-1;;;;4800:592:1:o;5397:367::-;5460:8;5470:6;5524:3;5517:4;5509:6;5505:17;5501:27;5491:55;;5542:1;5539;5532:12;5491:55;-1:-1:-1;5565:20:1;;5608:18;5597:30;;5594:50;;;5640:1;5637;5630:12;5594:50;5677:4;5669:6;5665:17;5653:29;;5737:3;5730:4;5720:6;5717:1;5713:14;5705:6;5701:27;5697:38;5694:47;5691:67;;;5754:1;5751;5744:12;5769:505;5864:6;5872;5880;5933:2;5921:9;5912:7;5908:23;5904:32;5901:52;;;5949:1;5946;5939:12;5901:52;5985:9;5972:23;5962:33;;6046:2;6035:9;6031:18;6018:32;6073:18;6065:6;6062:30;6059:50;;;6105:1;6102;6095:12;6059:50;6144:70;6206:7;6197:6;6186:9;6182:22;6144:70;:::i;:::-;5769:505;;6233:8;;-1:-1:-1;6118:96:1;;-1:-1:-1;;;;5769:505:1:o;6279:186::-;6338:6;6391:2;6379:9;6370:7;6366:23;6362:32;6359:52;;;6407:1;6404;6397:12;6359:52;6430:29;6449:9;6430:29;:::i;6655:366::-;6722:6;6730;6783:2;6771:9;6762:7;6758:23;6754:32;6751:52;;;6799:1;6796;6789:12;6751:52;6822:29;6841:9;6822:29;:::i;:::-;6812:39;;6901:2;6890:9;6886:18;6873:32;-1:-1:-1;;;;;6938:5:1;6934:38;6927:5;6924:49;6914:77;;6987:1;6984;6977:12;6914:77;7010:5;7000:15;;;6655:366;;;;;:::o;7026:254::-;7091:6;7099;7152:2;7140:9;7131:7;7127:23;7123:32;7120:52;;;7168:1;7165;7158:12;7120:52;7191:29;7210:9;7191:29;:::i;:::-;7181:39;;7239:35;7270:2;7259:9;7255:18;7239:35;:::i;:::-;7229:45;;7026:254;;;;;:::o;7285:437::-;7371:6;7379;7432:2;7420:9;7411:7;7407:23;7403:32;7400:52;;;7448:1;7445;7438:12;7400:52;7488:9;7475:23;7521:18;7513:6;7510:30;7507:50;;;7553:1;7550;7543:12;7507:50;7592:70;7654:7;7645:6;7634:9;7630:22;7592:70;:::i;:::-;7681:8;;7566:96;;-1:-1:-1;7285:437:1;-1:-1:-1;;;;7285:437:1:o;7727:667::-;7822:6;7830;7838;7846;7899:3;7887:9;7878:7;7874:23;7870:33;7867:53;;;7916:1;7913;7906:12;7867:53;7939:29;7958:9;7939:29;:::i;:::-;7929:39;;7987:38;8021:2;8010:9;8006:18;7987:38;:::i;:::-;7977:48;;8072:2;8061:9;8057:18;8044:32;8034:42;;8127:2;8116:9;8112:18;8099:32;8154:18;8146:6;8143:30;8140:50;;;8186:1;8183;8176:12;8140:50;8209:22;;8262:4;8254:13;;8250:27;-1:-1:-1;8240:55:1;;8291:1;8288;8281:12;8240:55;8314:74;8380:7;8375:2;8362:16;8357:2;8353;8349:11;8314:74;:::i;:::-;8304:84;;;7727:667;;;;;;;:::o;8399:127::-;8460:10;8455:3;8451:20;8448:1;8441:31;8491:4;8488:1;8481:15;8515:4;8512:1;8505:15;8531:343;8678:2;8663:18;;8711:1;8700:13;;8690:144;;8756:10;8751:3;8747:20;8744:1;8737:31;8791:4;8788:1;8781:15;8819:4;8816:1;8809:15;8690:144;8843:25;;;8531:343;:::o;9068:260::-;9136:6;9144;9197:2;9185:9;9176:7;9172:23;9168:32;9165:52;;;9213:1;9210;9203:12;9165:52;9236:29;9255:9;9236:29;:::i;:::-;9226:39;;9284:38;9318:2;9307:9;9303:18;9284:38;:::i;9333:127::-;9394:10;9389:3;9385:20;9382:1;9375:31;9425:4;9422:1;9415:15;9449:4;9446:1;9439:15;9465:168;9538:9;;;9569;;9586:15;;;9580:22;;9566:37;9556:71;;9607:18;;:::i;9638:127::-;9699:10;9694:3;9690:20;9687:1;9680:31;9730:4;9727:1;9720:15;9754:4;9751:1;9744:15;9770:120;9810:1;9836;9826:35;;9841:18;;:::i;:::-;-1:-1:-1;9875:9:1;;9770:120::o;9895:380::-;9974:1;9970:12;;;;10017;;;10038:61;;10092:4;10084:6;10080:17;10070:27;;10038:61;10145:2;10137:6;10134:14;10114:18;10111:38;10108:161;;10191:10;10186:3;10182:20;10179:1;10172:31;10226:4;10223:1;10216:15;10254:4;10251:1;10244:15;10108:161;;9895:380;;;:::o;10616:518::-;10718:2;10713:3;10710:11;10707:421;;;10754:5;10751:1;10744:16;10798:4;10795:1;10785:18;10868:2;10856:10;10852:19;10849:1;10845:27;10839:4;10835:38;10904:4;10892:10;10889:20;10886:47;;;-1:-1:-1;10927:4:1;10886:47;10982:2;10977:3;10973:12;10970:1;10966:20;10960:4;10956:31;10946:41;;11037:81;11055:2;11048:5;11045:13;11037:81;;;11114:1;11100:16;;11081:1;11070:13;11037:81;;;11041:3;;10616:518;;;:::o;11310:1345::-;11436:3;11430:10;11463:18;11455:6;11452:30;11449:56;;;11485:18;;:::i;:::-;11514:97;11604:6;11564:38;11596:4;11590:11;11564:38;:::i;:::-;11558:4;11514:97;:::i;:::-;11666:4;;11723:2;11712:14;;11740:1;11735:663;;;;12442:1;12459:6;12456:89;;;-1:-1:-1;12511:19:1;;;12505:26;12456:89;-1:-1:-1;;11267:1:1;11263:11;;;11259:24;11255:29;11245:40;11291:1;11287:11;;;11242:57;12558:81;;11705:944;;11735:663;10563:1;10556:14;;;10600:4;10587:18;;-1:-1:-1;;11771:20:1;;;11889:236;11903:7;11900:1;11897:14;11889:236;;;11992:19;;;11986:26;11971:42;;12084:27;;;;12052:1;12040:14;;;;11919:19;;11889:236;;;11893:3;12153:6;12144:7;12141:19;12138:201;;;12214:19;;;12208:26;-1:-1:-1;;12297:1:1;12293:14;;;12309:3;12289:24;12285:37;12281:42;12266:58;12251:74;;12138:201;-1:-1:-1;;;;;12385:1:1;12369:14;;;12365:22;12352:36;;-1:-1:-1;11310:1345:1:o;12660:1198::-;12784:18;12779:3;12776:27;12773:53;;;12806:18;;:::i;:::-;12835:94;12925:3;12885:38;12917:4;12911:11;12885:38;:::i;:::-;12879:4;12835:94;:::i;:::-;12955:1;12980:2;12975:3;12972:11;12997:1;12992:608;;;;13644:1;13661:3;13658:93;;;-1:-1:-1;13717:19:1;;;13704:33;13658:93;-1:-1:-1;;11267:1:1;11263:11;;;11259:24;11255:29;11245:40;11291:1;11287:11;;;11242:57;13764:78;;12965:887;;12992:608;10563:1;10556:14;;;10600:4;10587:18;;-1:-1:-1;;13028:17:1;;;13143:229;13157:7;13154:1;13151:14;13143:229;;;13246:19;;;13233:33;13218:49;;13353:4;13338:20;;;;13306:1;13294:14;;;;13173:12;13143:229;;;13147:3;13400;13391:7;13388:16;13385:159;;;13524:1;13520:6;13514:3;13508;13505:1;13501:11;13497:21;13493:34;13489:39;13476:9;13471:3;13467:19;13454:33;13450:79;13442:6;13435:95;13385:159;;;13587:1;13581:3;13578:1;13574:11;13570:19;13564:4;13557:33;12965:887;;12660:1198;;;:::o;13863:125::-;13928:9;;;13949:10;;;13946:36;;;13962:18;;:::i;13993:148::-;14081:4;14060:12;;;14074;;;14056:31;;14099:13;;14096:39;;;14115:18;;:::i;14505:175::-;14542:3;14586:4;14579:5;14575:16;14615:4;14606:7;14603:17;14600:43;;14623:18;;:::i;:::-;14672:1;14659:15;;14505:175;-1:-1:-1;;14505:175:1:o;15051:703::-;15278:3;15316:6;15310:13;15332:66;15391:6;15386:3;15379:4;15371:6;15367:17;15332:66;:::i;:::-;15461:13;;15420:16;;;;15483:70;15461:13;15420:16;15530:4;15518:17;;15483:70;:::i;:::-;15620:13;;15575:20;;;15642:70;15620:13;15575:20;15689:4;15677:17;;15642:70;:::i;:::-;15728:20;;15051:703;-1:-1:-1;;;;;15051:703:1:o;16278:489::-;-1:-1:-1;;;;;16547:15:1;;;16529:34;;16599:15;;16594:2;16579:18;;16572:43;16646:2;16631:18;;16624:34;;;16694:3;16689:2;16674:18;;16667:31;;;16472:4;;16715:46;;16741:19;;16733:6;16715:46;:::i;:::-;16707:54;16278:489;-1:-1:-1;;;;;;16278:489:1:o;16772:249::-;16841:6;16894:2;16882:9;16873:7;16869:23;16865:32;16862:52;;;16910:1;16907;16900:12;16862:52;16942:9;16936:16;16961:30;16985:5;16961:30;:::i;17026:135::-;17065:3;17086:17;;;17083:43;;17106:18;;:::i;:::-;-1:-1:-1;17153:1:1;17142:13;;17026:135::o;17483:112::-;17515:1;17541;17531:35;;17546:18;;:::i;:::-;-1:-1:-1;17580:9:1;;17483:112::o;17600:127::-;17661:10;17656:3;17652:20;17649:1;17642:31;17692:4;17689:1;17682:15;17716:4;17713:1;17706:15

Swarm Source

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