ETH Price: $3,440.99 (-1.14%)
Gas: 9 Gwei

Token

NONON FRIEND CARD (NONON_FRIEND)
 

Overview

Max Total Supply

459 NONON_FRIEND

Holders

459

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
realputtputt.eth
Balance
1 NONON_FRIEND
0x8f8f31c1042db38aa11424ea7b7e0bc2842a19a5
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:
NononFriendCard

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 9 : ERC721A.sol
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.2
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import './IERC721A.sol';

/**
 * @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 {
    // Reference type for token approval.
    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 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 {
        if (operator == _msgSenderERC721A()) revert ApproveToCaller();

        _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 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 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 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`.
                )

                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 0x80 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 32-byte word to store the length,
            // and 3 32-byte words to store a maximum of 78 digits. Total: 0x20 + 3 * 0x20 = 0x80.
            str := add(mload(0x40), 0x80)
            // Update the free memory pointer to allocate.
            mstore(0x40, str)

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

File 2 of 9 : IERC721A.sol
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.2
// Creator: Chiru Labs

pragma solidity ^0.8.4;

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

    /**
     * The caller cannot approve to their own address.
     */
    error ApproveToCaller();

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

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

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

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

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom}
     * for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the 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);
}

File 3 of 9 : INononFriendCard.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

interface INononFriendCard {
    /**
     * cannot transfer the soulbound token
     */
    error OnlyForYou();

    /**
     * cannot set collection address to zero address
     */
    error CollectionZeroAddress();

    /**
     * cannot add new level with a lower minimum
     */
    error LevelMinimumLowerThanExisting();

    /**
     * incorrect params given
     */
    error InvalidParams();

    /**
     * message exceeds size limit
     */
    error MessageTooLong();

    /**
     * svg data already set
     */
    error SvgAlreadySet();

    event MetadataUpdate(uint256 _tokenId);

    event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);

    event Locked(uint256 tokenId);

    function registerTokenMovement(address from, address to, uint256 collectionTokenStartId, uint256 quantity)
        external;

    function mintTo(address to) external;

    function hasToken(address receiver) external returns (bool);
}

File 4 of 9 : NononFriendCard.sol
// SPDX-License-Identifier: MIT 

/// @title NONON FRIEND CARD - YOUR SPECIAL GIFT

pragma solidity 0.8.4;

import "../ERC721A.sol";
import "../IERC721A.sol";
import "solady/src/auth/OwnableRoles.sol";
import "solady/src/utils/Base64.sol";
import "solady/src/utils/SSTORE2.sol";
import "solady/src/utils/LibBitmap.sol";

import "./INononFriendCard.sol";

contract NononFriendCard is INononFriendCard, ERC721A, OwnableRoles {
    using LibBitmap for LibBitmap.Bitmap;

    // track tokens that have been collected by a given address
    mapping(address => LibBitmap.Bitmap) private receivedBitmap;
    mapping(address => LibBitmap.Bitmap) private sentBitmap;

    string public constant TOKEN_NAME = "NONON FRIEND CARD: ";
    string public constant DEFAULT_DESC = "share your message at nonon.house";
    uint256 public constant NONON_MAX_SUPPLY = 5000;

    address public immutable collectionAddress;


    // address where bytes for base SVG are stored
    address private baseSvgPointer;
    bool private baseSvgPointerLocked;
    // address where bytes for svg defs are stored
    address private defsSvgPointer;
    bool private defsSvgPointerLocked;
    // address where level sprites are stored
    address private spritesSvgPointer;
    bool private spritesSvgPointerLocked;

    struct Level {
        uint256 minimum;
        string name;
        string colorGradient;
        uint16 spriteIndex;
        uint16 spriteLength;
    }

    struct LevelImageData {
        string name;
        string colorGradient;
        uint16 spriteIndex;
        uint16 spriteLength;
        uint256 cap;
    }

    // the evolution levels of the token
    Level[] public levels;

    struct TokenPoints {
        uint256 id;
        address owner;
        uint256 points;
    }

    // for easy lookup
    mapping(address => uint256) public tokenOf;

    // user messages (tokenId => message)
    mapping(uint256 => string) public messages;

    constructor(address tokenCollectionAddress) ERC721A("NONON FRIEND CARD", "NONON_FRIEND") {
        _setOwner(msg.sender);
        collectionAddress = tokenCollectionAddress;

        levels.push(Level(0, "ANGELS", "grad-1", 0, 288));
        levels.push(Level(10, "ARCHANGELS", "grad-2", 288, 652));
        levels.push(Level(50, "PRINCIPALITIES", "grad-3", 940, 758));
        levels.push(Level(150, "VIRTUES", "grad-4", 1698, 646));
        levels.push(Level(500, "DOMINIONS", "grad-5", 2344, 984));
        levels.push(Level(1500, "THRONES", "grad-6", 3328, 817));
        levels.push(Level(3500, "CHERUBIM", "grad-7", 4145, 758));
        levels.push(Level(7500, "SERAPHIM", "grad-8", 4903, 709));
    }

    function setBaseSvgPointer(bytes memory baseImage) public onlyOwner {
        if (baseSvgPointerLocked) revert SvgAlreadySet();

        baseSvgPointer = SSTORE2.write(baseImage);
        baseSvgPointerLocked = true;
    }

    function setDefsSvgPointer(bytes memory defs) public onlyOwner {
        if (defsSvgPointerLocked) revert SvgAlreadySet();

        defsSvgPointer = SSTORE2.write(defs);
        defsSvgPointerLocked = true;
    }

    function setSpritesSvgPointer(bytes memory spriteImages) public onlyOwner {
        if (spritesSvgPointerLocked) revert SvgAlreadySet();

        spritesSvgPointer = SSTORE2.write(spriteImages);
        spritesSvgPointerLocked = true;
    }

    function mintTo(address to) external override onlyCollection {
        uint256 id = _nextTokenId();
        tokenOf[to] = id;
        _mint(to, 1);

        emit Locked(id);
    }

    function burnToken(uint256 tokenId) public {
        delete tokenOf[ownerOf(tokenId)];
        _burn(tokenId, true);
    }

    // set custom message for a token
    function setMessage(uint256 _tokenId, string calldata _message) public {
        if (ownerOf(_tokenId) != msg.sender) revert Unauthorized();
        if (bytes(_message).length > 256) revert MessageTooLong();

        messages[_tokenId] = _message;
        emit MetadataUpdate(_tokenId);
    }

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

        uint256 tokenPoints = points(tokenId);
        LevelImageData memory level = levelData(tokenPoints);
        string memory message = tokenMessage(tokenId);

        string memory baseUrl = "data:application/json;base64,";
        return string(
            abi.encodePacked(
                baseUrl,
                Base64.encode(
                    bytes(
                        abi.encodePacked(
                            '{"name":"',
                            bytes.concat(bytes(TOKEN_NAME), bytes(level.name)),
                            '",',
                            '"description":"',
                            message,
                            '",',
                            '"attributes":[{"trait_type":"Points","max_value":',
                            _toString(level.cap),
                            ',"value":',
                            _toString(tokenPoints),
                            '}, {"trait_type":"Level","value":"',
                            level.name,
                            '"}],',
                            '"image":"',
                            buildSvg(level.colorGradient, level.spriteIndex, level.spriteLength, message),
                            '"}'
                        )
                    )
                )
            )
        );
    }

    function tokenMessage(uint256 tokenId) public view returns (string memory) {
        string memory message = messages[tokenId];
        if (bytes(message).length > 0) {
            return message;
        } else {
            return DEFAULT_DESC;
        }
    }

    // construct image svg
    function buildSvg(string memory colorGradient, uint16 spriteIndex, uint16 spriteLength, string memory message)
        internal
        view
        returns (string memory)
    {
        string memory baseUrl = "data:image/svg+xml;base64,";
        bytes memory baseSvg = SSTORE2.read(baseSvgPointer);
        bytes memory spritesSvg = SSTORE2.read(spritesSvgPointer);
        bytes memory defs = SSTORE2.read(defsSvgPointer);

        return string(
            abi.encodePacked(
                baseUrl,
                Base64.encode(
                    bytes(
                        abi.encodePacked(
                            '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 1080 1080"><path fill="rgba(255,255,255,0)" d="M0 0h1080v1080H0z" />',
                            '<path fill="url(#',
                            colorGradient,
                            ')" d="M24 40a16 16 0 0 1 16-16h1000a16 16 0 0 1 16 16v914a16 16 0 0 1-16 16H114.5a24 24 0 0 0-17.6 7.7l-59 63.4a8 8 0 0 1-13.9-5.4V40Z" />',
                            baseSvg,
                            getSpriteSubstring(spritesSvg, spriteIndex, spriteLength),
                            '<text xml:space="preserve" fill="#009DF5" font-family="Courier" font-size="24" letter-spacing="0em" style="white-space:pre"><tspan x="144" y="1044.9">',
                            message,
                            "</tspan></text>",
                            defs,
                            "</svg>"
                        )
                    )
                )
            )
        );
    }

    function getSpriteSubstring(bytes memory spritesSvg, uint16 spriteIndex, uint16 spriteLength)
        internal
        pure
        returns (bytes memory)
    {
        bytes memory sprite = new bytes(spriteLength);

        for (uint256 i = 0; i < sprite.length; i++) {
            sprite[i] = spritesSvg[i + spriteIndex];
        }

        return sprite;
    }

    // get metadata for token display based on a given points value
    function levelData(uint256 tokenPoints) internal view returns (LevelImageData memory levelImageData) {
        for (uint256 i = levels.length; i > 0;) {
            Level memory level = levels[i - 1];
            if (tokenPoints >= level.minimum) {
                if (i < levels.length) {
                    // there is at least one level above current, so get its minimum
                    Level memory nextLevel = levels[i];
                    return LevelImageData(
                        level.name, level.colorGradient, level.spriteIndex, level.spriteLength, nextLevel.minimum
                    );
                } else {
                    // highest level
                    uint256 maxPoints = IERC721A(collectionAddress).totalSupply() * 2;
                    return LevelImageData(level.name, level.colorGradient, level.spriteIndex, level.spriteLength, maxPoints);
                }
            }
            unchecked {
                --i;
            }
        }
    }

    // prevent transfer (except mint and burn)
    function _beforeTokenTransfers(address from, address to, uint256, uint256) internal pure override {
        if (from != address(0) && to != address(0)) {
            revert OnlyForYou();
        }
    }

    // add ID for associated sequential tokens to appropriate lists
    function registerTokenMovement(address from, address to, uint256 collectionTokenStartId, uint256 quantity)
        external
        override
        onlyCollection
    {
        if (from != address(0)) {
            if (to != from) {
                sentBitmap[from].setBatch(collectionTokenStartId, quantity);
            }
        }

        if (to != address(0)) {
            receivedBitmap[to].setBatch(collectionTokenStartId, quantity);
        }

        emit BatchMetadataUpdate(1, type(uint256).max);
    }

    // total points accumulated by a holder
    function points(uint256 tokenId) public view returns (uint256) {
        address owner = ownerOf(tokenId);
        uint256 max = IERC721A(collectionAddress).totalSupply() + 1;

        return receivedBitmap[owner].popCount(1, max) + sentBitmap[owner].popCount(1, max);
    }

    // convenience function to get point information in a token range
    // note that this is expensive and most likely will require multiple calls to cover large ranges.
    function tokenPointsInRange(uint256 startId, uint256 endId) external view returns (TokenPoints[] memory) {
        if (endId < startId) revert InvalidParams();

        TokenPoints[] memory tokenPoints = new TokenPoints[]((endId - startId) + 1);
        uint256 max = IERC721A(collectionAddress).totalSupply() + 1;

        uint256 pointsIndex;
        for (uint256 i = startId; i <= endId;) {
            if (_exists(i)) {
                address owner = ownerOf(i);
                uint256 totalPoints = receivedBitmap[owner].popCount(1, max) + sentBitmap[owner].popCount(1, max);

                tokenPoints[pointsIndex] = TokenPoints({id: i, owner: owner, points: totalPoints});
                ++pointsIndex;
            }
            ++i;
        }

        return tokenPoints;
    }

    // check if given address is a holder of the token
    function hasToken(address receiver) public view override returns (bool) {
        return balanceOf(receiver) > 0;
    }

    // check if given address has ever received tokenId
    function hasReceivedToken(address owner, uint256 tokenId) external view returns (bool) {
        return receivedBitmap[owner].get(tokenId);
    }

    // check if given address has ever sent tokenId
    function hasSentToken(address owner, uint256 tokenId) external view returns (bool) {
        return sentBitmap[owner].get(tokenId);
    }

    function tokenStatusMap(address owner, bool sent) external view returns (uint256[] memory received) {
        uint256 maxWordIndex = NONON_MAX_SUPPLY >> 8;
        uint256[] memory words = new uint256[](maxWordIndex + 1);
        for (uint256 i = 0; i <= maxWordIndex; i++) {
            words[i] = (sent ? sentBitmap[owner].map[i] : receivedBitmap[owner].map[i]);
        }
        return words;
    }

    function _startTokenId() internal view virtual override returns (uint256) {
        return 1;
    }

    modifier onlyCollection() {
        if (msg.sender != collectionAddress) {
            revert Unauthorized();
        }
        _;
    }
}

File 5 of 9 : OwnableRoles.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner and multiroles authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/OwnableRoles.sol)
/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173)
/// for compatibility, the nomenclature for the 2-step ownership handover and roles
/// may be unique to this codebase.
abstract contract OwnableRoles {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev `bytes4(keccak256(bytes("Unauthorized()")))`.
    uint256 private constant _UNAUTHORIZED_ERROR_SELECTOR = 0x82b42900;

    /// @dev `bytes4(keccak256(bytes("NewOwnerIsZeroAddress()")))`.
    uint256 private constant _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR = 0x7448fbae;

    /// @dev `bytes4(keccak256(bytes("NoHandoverRequest()")))`.
    uint256 private constant _NO_HANDOVER_REQUEST_ERROR_SELECTOR = 0x6f5e8818;

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

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev The `user`'s roles is updated to `roles`.
    /// Each bit of `roles` represents whether the role is set.
    event RolesUpdated(address indexed user, uint256 indexed roles);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

    /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
    uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
        0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;

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

    /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
    /// It is intentionally choosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    ///
    /// The role slot of `user` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT))
    ///     let roleSlot := keccak256(0x00, 0x20)
    /// ```
    /// This automatically ignores the upper bits of the `user` in case
    /// they are not clean, as well as keep the `keccak256` under 32-bytes.
    uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Store the new value.
            sstore(not(_OWNER_SLOT_NOT), newOwner)
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let ownerSlot := not(_OWNER_SLOT_NOT)
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
            // Store the new value.
            sstore(ownerSlot, newOwner)
        }
    }

    /// @dev Grants the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn on.
    function _grantRoles(address user, uint256 roles) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT))
            let roleSlot := keccak256(0x00, 0x20)
            // Load the current value and `or` it with `roles`.
            let newRoles := or(sload(roleSlot), roles)
            // Store the new value.
            sstore(roleSlot, newRoles)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, shl(96, user)), newRoles)
        }
    }

    /// @dev Removes the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn off.
    function _removeRoles(address user, uint256 roles) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT))
            let roleSlot := keccak256(0x00, 0x20)
            // Load the current value.
            let currentRoles := sload(roleSlot)
            // Use `and` to compute the intersection of `currentRoles` and `roles`,
            // `xor` it with `currentRoles` to flip the bits in the intersection.
            let newRoles := xor(currentRoles, and(currentRoles, roles))
            // Then, store the new value.
            sstore(roleSlot, newRoles)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, shl(96, user)), newRoles)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Reverts if the `newOwner` is the zero address.
            if iszero(newOwner) {
                mstore(0x00, _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR)
                revert(0x1c, 0x04)
            }
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), newOwner)
            // Store the new value.
            sstore(not(_OWNER_SLOT_NOT), newOwner)
        }
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), 0)
            // Store the new value.
            sstore(not(_OWNER_SLOT_NOT), 0)
        }
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will be automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to 1.
                mstore(0x00, or(shl(96, caller()), _HANDOVER_SLOT_SEED))
                sstore(keccak256(0x00, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x00, or(shl(96, caller()), _HANDOVER_SLOT_SEED))
            sstore(keccak256(0x00, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits.
            pendingOwner := shr(96, shl(96, pendingOwner))
            // Compute and set the handover slot to 0.
            mstore(0x00, or(shl(96, pendingOwner), _HANDOVER_SLOT_SEED))
            let handoverSlot := keccak256(0x00, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, _NO_HANDOVER_REQUEST_ERROR_SELECTOR)
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), pendingOwner)
            // Store the new value.
            sstore(not(_OWNER_SLOT_NOT), pendingOwner)
        }
    }

    /// @dev Allows the owner to grant `user` `roles`.
    /// If the `user` already has a role, then it will be an no-op for the role.
    function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _grantRoles(user, roles);
    }

    /// @dev Allows the owner to remove `user` `roles`.
    /// If the `user` does not have a role, then it will be an no-op for the role.
    function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _removeRoles(user, roles);
    }

    /// @dev Allow the caller to remove their own roles.
    /// If the caller does not have a role, then it will be an no-op for the role.
    function renounceRoles(uint256 roles) public payable virtual {
        _removeRoles(msg.sender, roles);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(not(_OWNER_SLOT_NOT))
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x00, or(shl(96, pendingOwner), _HANDOVER_SLOT_SEED))
            // Load the handover slot.
            result := sload(keccak256(0x00, 0x20))
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    function ownershipHandoverValidFor() public view virtual returns (uint64) {
        return 48 * 3600;
    }

    /// @dev Returns whether `user` has any of `roles`.
    function hasAnyRole(address user, uint256 roles) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT))
            // Load the stored value, and set the result to whether the
            // `and` intersection of the value and `roles` is not zero.
            result := iszero(iszero(and(sload(keccak256(0x00, 0x20)), roles)))
        }
    }

    /// @dev Returns whether `user` has all of `roles`.
    function hasAllRoles(address user, uint256 roles) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT))
            // Whether the stored value is contains all the set bits in `roles`.
            result := eq(and(sload(keccak256(0x00, 0x20)), roles), roles)
        }
    }

    /// @dev Returns the roles of `user`.
    function rolesOf(address user) public view virtual returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT))
            // Load the stored value.
            roles := sload(keccak256(0x00, 0x20))
        }
    }

    /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    function rolesFromOrdinals(uint8[] memory ordinals) public pure returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            // Skip the length slot.
            let o := add(ordinals, 0x20)
            // `shl` 5 is equivalent to multiplying by 0x20.
            let end := add(o, shl(5, mload(ordinals)))
            // prettier-ignore
            for {} iszero(eq(o, end)) { o := add(o, 0x20) } {
                roles := or(roles, shl(and(mload(o), 0xff), 1))
            }
        }
    }

    /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    function ordinalsFromRoles(uint256 roles) public pure returns (uint8[] memory ordinals) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the pointer to the free memory.
            let ptr := add(mload(0x40), 0x20)
            // The absence of lookup tables, De Bruijn, etc., here is intentional for
            // smaller bytecode, as this function is not meant to be called on-chain.
            // prettier-ignore
            for { let i := 0 } 1 { i := add(i, 1) } {
                mstore(ptr, i)
                // `shr` 5 is equivalent to multiplying by 0x20.
                // Push back into the ordinals array if the bit is set.
                ptr := add(ptr, shl(5, and(roles, 1)))
                roles := shr(1, roles)
                // prettier-ignore
                if iszero(roles) { break }
            }
            // Set `ordinals` to the start of the free memory.
            ordinals := mload(0x40)
            // Allocate the memory.
            mstore(0x40, ptr)
            // Store the length of `ordinals`.
            mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
        }
    }

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

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR)
                revert(0x1c, 0x04)
            }
        }
        _;
    }

    /// @dev Marks a function as only callable by an account with `roles`.
    modifier onlyRoles(uint256 roles) virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT))
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x00, 0x20)), roles)) {
                mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR)
                revert(0x1c, 0x04)
            }
        }
        _;
    }

    /// @dev Marks a function as only callable by the owner or by an account
    /// with `roles`. Checks for ownership first, then lazily checks for roles.
    modifier onlyOwnerOrRoles(uint256 roles) virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner.
            if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                // Compute the role slot.
                mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT))
                // Load the stored value, and if the `and` intersection
                // of the value and `roles` is zero, revert.
                if iszero(and(sload(keccak256(0x00, 0x20)), roles)) {
                    mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR)
                    revert(0x1c, 0x04)
                }
            }
        }
        _;
    }

    /// @dev Marks a function as only callable by an account with `roles`
    /// or the owner. Checks for roles first, then lazily checks for ownership.
    modifier onlyRolesOrOwner(uint256 roles) virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT))
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x00, 0x20)), roles)) {
                // If the caller is not the stored owner.
                if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                    mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR)
                    revert(0x1c, 0x04)
                }
            }
        }
        _;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ROLE CONSTANTS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // IYKYK

    uint256 internal constant _ROLE_0 = 1 << 0;
    uint256 internal constant _ROLE_1 = 1 << 1;
    uint256 internal constant _ROLE_2 = 1 << 2;
    uint256 internal constant _ROLE_3 = 1 << 3;
    uint256 internal constant _ROLE_4 = 1 << 4;
    uint256 internal constant _ROLE_5 = 1 << 5;
    uint256 internal constant _ROLE_6 = 1 << 6;
    uint256 internal constant _ROLE_7 = 1 << 7;
    uint256 internal constant _ROLE_8 = 1 << 8;
    uint256 internal constant _ROLE_9 = 1 << 9;
    uint256 internal constant _ROLE_10 = 1 << 10;
    uint256 internal constant _ROLE_11 = 1 << 11;
    uint256 internal constant _ROLE_12 = 1 << 12;
    uint256 internal constant _ROLE_13 = 1 << 13;
    uint256 internal constant _ROLE_14 = 1 << 14;
    uint256 internal constant _ROLE_15 = 1 << 15;
    uint256 internal constant _ROLE_16 = 1 << 16;
    uint256 internal constant _ROLE_17 = 1 << 17;
    uint256 internal constant _ROLE_18 = 1 << 18;
    uint256 internal constant _ROLE_19 = 1 << 19;
    uint256 internal constant _ROLE_20 = 1 << 20;
    uint256 internal constant _ROLE_21 = 1 << 21;
    uint256 internal constant _ROLE_22 = 1 << 22;
    uint256 internal constant _ROLE_23 = 1 << 23;
    uint256 internal constant _ROLE_24 = 1 << 24;
    uint256 internal constant _ROLE_25 = 1 << 25;
    uint256 internal constant _ROLE_26 = 1 << 26;
    uint256 internal constant _ROLE_27 = 1 << 27;
    uint256 internal constant _ROLE_28 = 1 << 28;
    uint256 internal constant _ROLE_29 = 1 << 29;
    uint256 internal constant _ROLE_30 = 1 << 30;
    uint256 internal constant _ROLE_31 = 1 << 31;
    uint256 internal constant _ROLE_32 = 1 << 32;
    uint256 internal constant _ROLE_33 = 1 << 33;
    uint256 internal constant _ROLE_34 = 1 << 34;
    uint256 internal constant _ROLE_35 = 1 << 35;
    uint256 internal constant _ROLE_36 = 1 << 36;
    uint256 internal constant _ROLE_37 = 1 << 37;
    uint256 internal constant _ROLE_38 = 1 << 38;
    uint256 internal constant _ROLE_39 = 1 << 39;
    uint256 internal constant _ROLE_40 = 1 << 40;
    uint256 internal constant _ROLE_41 = 1 << 41;
    uint256 internal constant _ROLE_42 = 1 << 42;
    uint256 internal constant _ROLE_43 = 1 << 43;
    uint256 internal constant _ROLE_44 = 1 << 44;
    uint256 internal constant _ROLE_45 = 1 << 45;
    uint256 internal constant _ROLE_46 = 1 << 46;
    uint256 internal constant _ROLE_47 = 1 << 47;
    uint256 internal constant _ROLE_48 = 1 << 48;
    uint256 internal constant _ROLE_49 = 1 << 49;
    uint256 internal constant _ROLE_50 = 1 << 50;
    uint256 internal constant _ROLE_51 = 1 << 51;
    uint256 internal constant _ROLE_52 = 1 << 52;
    uint256 internal constant _ROLE_53 = 1 << 53;
    uint256 internal constant _ROLE_54 = 1 << 54;
    uint256 internal constant _ROLE_55 = 1 << 55;
    uint256 internal constant _ROLE_56 = 1 << 56;
    uint256 internal constant _ROLE_57 = 1 << 57;
    uint256 internal constant _ROLE_58 = 1 << 58;
    uint256 internal constant _ROLE_59 = 1 << 59;
    uint256 internal constant _ROLE_60 = 1 << 60;
    uint256 internal constant _ROLE_61 = 1 << 61;
    uint256 internal constant _ROLE_62 = 1 << 62;
    uint256 internal constant _ROLE_63 = 1 << 63;
    uint256 internal constant _ROLE_64 = 1 << 64;
    uint256 internal constant _ROLE_65 = 1 << 65;
    uint256 internal constant _ROLE_66 = 1 << 66;
    uint256 internal constant _ROLE_67 = 1 << 67;
    uint256 internal constant _ROLE_68 = 1 << 68;
    uint256 internal constant _ROLE_69 = 1 << 69;
    uint256 internal constant _ROLE_70 = 1 << 70;
    uint256 internal constant _ROLE_71 = 1 << 71;
    uint256 internal constant _ROLE_72 = 1 << 72;
    uint256 internal constant _ROLE_73 = 1 << 73;
    uint256 internal constant _ROLE_74 = 1 << 74;
    uint256 internal constant _ROLE_75 = 1 << 75;
    uint256 internal constant _ROLE_76 = 1 << 76;
    uint256 internal constant _ROLE_77 = 1 << 77;
    uint256 internal constant _ROLE_78 = 1 << 78;
    uint256 internal constant _ROLE_79 = 1 << 79;
    uint256 internal constant _ROLE_80 = 1 << 80;
    uint256 internal constant _ROLE_81 = 1 << 81;
    uint256 internal constant _ROLE_82 = 1 << 82;
    uint256 internal constant _ROLE_83 = 1 << 83;
    uint256 internal constant _ROLE_84 = 1 << 84;
    uint256 internal constant _ROLE_85 = 1 << 85;
    uint256 internal constant _ROLE_86 = 1 << 86;
    uint256 internal constant _ROLE_87 = 1 << 87;
    uint256 internal constant _ROLE_88 = 1 << 88;
    uint256 internal constant _ROLE_89 = 1 << 89;
    uint256 internal constant _ROLE_90 = 1 << 90;
    uint256 internal constant _ROLE_91 = 1 << 91;
    uint256 internal constant _ROLE_92 = 1 << 92;
    uint256 internal constant _ROLE_93 = 1 << 93;
    uint256 internal constant _ROLE_94 = 1 << 94;
    uint256 internal constant _ROLE_95 = 1 << 95;
    uint256 internal constant _ROLE_96 = 1 << 96;
    uint256 internal constant _ROLE_97 = 1 << 97;
    uint256 internal constant _ROLE_98 = 1 << 98;
    uint256 internal constant _ROLE_99 = 1 << 99;
    uint256 internal constant _ROLE_100 = 1 << 100;
    uint256 internal constant _ROLE_101 = 1 << 101;
    uint256 internal constant _ROLE_102 = 1 << 102;
    uint256 internal constant _ROLE_103 = 1 << 103;
    uint256 internal constant _ROLE_104 = 1 << 104;
    uint256 internal constant _ROLE_105 = 1 << 105;
    uint256 internal constant _ROLE_106 = 1 << 106;
    uint256 internal constant _ROLE_107 = 1 << 107;
    uint256 internal constant _ROLE_108 = 1 << 108;
    uint256 internal constant _ROLE_109 = 1 << 109;
    uint256 internal constant _ROLE_110 = 1 << 110;
    uint256 internal constant _ROLE_111 = 1 << 111;
    uint256 internal constant _ROLE_112 = 1 << 112;
    uint256 internal constant _ROLE_113 = 1 << 113;
    uint256 internal constant _ROLE_114 = 1 << 114;
    uint256 internal constant _ROLE_115 = 1 << 115;
    uint256 internal constant _ROLE_116 = 1 << 116;
    uint256 internal constant _ROLE_117 = 1 << 117;
    uint256 internal constant _ROLE_118 = 1 << 118;
    uint256 internal constant _ROLE_119 = 1 << 119;
    uint256 internal constant _ROLE_120 = 1 << 120;
    uint256 internal constant _ROLE_121 = 1 << 121;
    uint256 internal constant _ROLE_122 = 1 << 122;
    uint256 internal constant _ROLE_123 = 1 << 123;
    uint256 internal constant _ROLE_124 = 1 << 124;
    uint256 internal constant _ROLE_125 = 1 << 125;
    uint256 internal constant _ROLE_126 = 1 << 126;
    uint256 internal constant _ROLE_127 = 1 << 127;
    uint256 internal constant _ROLE_128 = 1 << 128;
    uint256 internal constant _ROLE_129 = 1 << 129;
    uint256 internal constant _ROLE_130 = 1 << 130;
    uint256 internal constant _ROLE_131 = 1 << 131;
    uint256 internal constant _ROLE_132 = 1 << 132;
    uint256 internal constant _ROLE_133 = 1 << 133;
    uint256 internal constant _ROLE_134 = 1 << 134;
    uint256 internal constant _ROLE_135 = 1 << 135;
    uint256 internal constant _ROLE_136 = 1 << 136;
    uint256 internal constant _ROLE_137 = 1 << 137;
    uint256 internal constant _ROLE_138 = 1 << 138;
    uint256 internal constant _ROLE_139 = 1 << 139;
    uint256 internal constant _ROLE_140 = 1 << 140;
    uint256 internal constant _ROLE_141 = 1 << 141;
    uint256 internal constant _ROLE_142 = 1 << 142;
    uint256 internal constant _ROLE_143 = 1 << 143;
    uint256 internal constant _ROLE_144 = 1 << 144;
    uint256 internal constant _ROLE_145 = 1 << 145;
    uint256 internal constant _ROLE_146 = 1 << 146;
    uint256 internal constant _ROLE_147 = 1 << 147;
    uint256 internal constant _ROLE_148 = 1 << 148;
    uint256 internal constant _ROLE_149 = 1 << 149;
    uint256 internal constant _ROLE_150 = 1 << 150;
    uint256 internal constant _ROLE_151 = 1 << 151;
    uint256 internal constant _ROLE_152 = 1 << 152;
    uint256 internal constant _ROLE_153 = 1 << 153;
    uint256 internal constant _ROLE_154 = 1 << 154;
    uint256 internal constant _ROLE_155 = 1 << 155;
    uint256 internal constant _ROLE_156 = 1 << 156;
    uint256 internal constant _ROLE_157 = 1 << 157;
    uint256 internal constant _ROLE_158 = 1 << 158;
    uint256 internal constant _ROLE_159 = 1 << 159;
    uint256 internal constant _ROLE_160 = 1 << 160;
    uint256 internal constant _ROLE_161 = 1 << 161;
    uint256 internal constant _ROLE_162 = 1 << 162;
    uint256 internal constant _ROLE_163 = 1 << 163;
    uint256 internal constant _ROLE_164 = 1 << 164;
    uint256 internal constant _ROLE_165 = 1 << 165;
    uint256 internal constant _ROLE_166 = 1 << 166;
    uint256 internal constant _ROLE_167 = 1 << 167;
    uint256 internal constant _ROLE_168 = 1 << 168;
    uint256 internal constant _ROLE_169 = 1 << 169;
    uint256 internal constant _ROLE_170 = 1 << 170;
    uint256 internal constant _ROLE_171 = 1 << 171;
    uint256 internal constant _ROLE_172 = 1 << 172;
    uint256 internal constant _ROLE_173 = 1 << 173;
    uint256 internal constant _ROLE_174 = 1 << 174;
    uint256 internal constant _ROLE_175 = 1 << 175;
    uint256 internal constant _ROLE_176 = 1 << 176;
    uint256 internal constant _ROLE_177 = 1 << 177;
    uint256 internal constant _ROLE_178 = 1 << 178;
    uint256 internal constant _ROLE_179 = 1 << 179;
    uint256 internal constant _ROLE_180 = 1 << 180;
    uint256 internal constant _ROLE_181 = 1 << 181;
    uint256 internal constant _ROLE_182 = 1 << 182;
    uint256 internal constant _ROLE_183 = 1 << 183;
    uint256 internal constant _ROLE_184 = 1 << 184;
    uint256 internal constant _ROLE_185 = 1 << 185;
    uint256 internal constant _ROLE_186 = 1 << 186;
    uint256 internal constant _ROLE_187 = 1 << 187;
    uint256 internal constant _ROLE_188 = 1 << 188;
    uint256 internal constant _ROLE_189 = 1 << 189;
    uint256 internal constant _ROLE_190 = 1 << 190;
    uint256 internal constant _ROLE_191 = 1 << 191;
    uint256 internal constant _ROLE_192 = 1 << 192;
    uint256 internal constant _ROLE_193 = 1 << 193;
    uint256 internal constant _ROLE_194 = 1 << 194;
    uint256 internal constant _ROLE_195 = 1 << 195;
    uint256 internal constant _ROLE_196 = 1 << 196;
    uint256 internal constant _ROLE_197 = 1 << 197;
    uint256 internal constant _ROLE_198 = 1 << 198;
    uint256 internal constant _ROLE_199 = 1 << 199;
    uint256 internal constant _ROLE_200 = 1 << 200;
    uint256 internal constant _ROLE_201 = 1 << 201;
    uint256 internal constant _ROLE_202 = 1 << 202;
    uint256 internal constant _ROLE_203 = 1 << 203;
    uint256 internal constant _ROLE_204 = 1 << 204;
    uint256 internal constant _ROLE_205 = 1 << 205;
    uint256 internal constant _ROLE_206 = 1 << 206;
    uint256 internal constant _ROLE_207 = 1 << 207;
    uint256 internal constant _ROLE_208 = 1 << 208;
    uint256 internal constant _ROLE_209 = 1 << 209;
    uint256 internal constant _ROLE_210 = 1 << 210;
    uint256 internal constant _ROLE_211 = 1 << 211;
    uint256 internal constant _ROLE_212 = 1 << 212;
    uint256 internal constant _ROLE_213 = 1 << 213;
    uint256 internal constant _ROLE_214 = 1 << 214;
    uint256 internal constant _ROLE_215 = 1 << 215;
    uint256 internal constant _ROLE_216 = 1 << 216;
    uint256 internal constant _ROLE_217 = 1 << 217;
    uint256 internal constant _ROLE_218 = 1 << 218;
    uint256 internal constant _ROLE_219 = 1 << 219;
    uint256 internal constant _ROLE_220 = 1 << 220;
    uint256 internal constant _ROLE_221 = 1 << 221;
    uint256 internal constant _ROLE_222 = 1 << 222;
    uint256 internal constant _ROLE_223 = 1 << 223;
    uint256 internal constant _ROLE_224 = 1 << 224;
    uint256 internal constant _ROLE_225 = 1 << 225;
    uint256 internal constant _ROLE_226 = 1 << 226;
    uint256 internal constant _ROLE_227 = 1 << 227;
    uint256 internal constant _ROLE_228 = 1 << 228;
    uint256 internal constant _ROLE_229 = 1 << 229;
    uint256 internal constant _ROLE_230 = 1 << 230;
    uint256 internal constant _ROLE_231 = 1 << 231;
    uint256 internal constant _ROLE_232 = 1 << 232;
    uint256 internal constant _ROLE_233 = 1 << 233;
    uint256 internal constant _ROLE_234 = 1 << 234;
    uint256 internal constant _ROLE_235 = 1 << 235;
    uint256 internal constant _ROLE_236 = 1 << 236;
    uint256 internal constant _ROLE_237 = 1 << 237;
    uint256 internal constant _ROLE_238 = 1 << 238;
    uint256 internal constant _ROLE_239 = 1 << 239;
    uint256 internal constant _ROLE_240 = 1 << 240;
    uint256 internal constant _ROLE_241 = 1 << 241;
    uint256 internal constant _ROLE_242 = 1 << 242;
    uint256 internal constant _ROLE_243 = 1 << 243;
    uint256 internal constant _ROLE_244 = 1 << 244;
    uint256 internal constant _ROLE_245 = 1 << 245;
    uint256 internal constant _ROLE_246 = 1 << 246;
    uint256 internal constant _ROLE_247 = 1 << 247;
    uint256 internal constant _ROLE_248 = 1 << 248;
    uint256 internal constant _ROLE_249 = 1 << 249;
    uint256 internal constant _ROLE_250 = 1 << 250;
    uint256 internal constant _ROLE_251 = 1 << 251;
    uint256 internal constant _ROLE_252 = 1 << 252;
    uint256 internal constant _ROLE_253 = 1 << 253;
    uint256 internal constant _ROLE_254 = 1 << 254;
    uint256 internal constant _ROLE_255 = 1 << 255;
}

File 6 of 9 : Base64.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library to encode strings in Base64.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)
/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>.
library Base64 {
    /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
    /// See: https://datatracker.ietf.org/doc/html/rfc4648
    /// @param fileSafe  Whether to replace '+' with '-' and '/' with '_'.
    /// @param noPadding Whether to strip away the padding.
    function encode(
        bytes memory data,
        bool fileSafe,
        bool noPadding
    ) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let dataLength := mload(data)

            if dataLength {
                // Multiply by 4/3 rounded up.
                // The `shl(2, ...)` is equivalent to multiplying by 4.
                let encodedLength := shl(2, div(add(dataLength, 2), 3))

                // Set `result` to point to the start of the free memory.
                result := mload(0x40)

                // Store the table into the scratch space.
                // Offsetted by -1 byte so that the `mload` will load the character.
                // We will rewrite the free memory pointer at `0x40` later with
                // the allocated size.
                // The magic constant 0x0230 will translate "-_" + "+/".
                mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
                mstore(0x3f, sub("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0230)))

                // Skip the first slot, which stores the length.
                let ptr := add(result, 0x20)
                let end := add(ptr, encodedLength)

                // Run over the input, 3 bytes at a time.
                // prettier-ignore
                for {} 1 {} {
                    data := add(data, 3) // Advance 3 bytes.
                    let input := mload(data)

                    // Write 4 bytes. Optimized for fewer stack operations.
                    mstore8(    ptr    , mload(and(shr(18, input), 0x3F)))
                    mstore8(add(ptr, 1), mload(and(shr(12, input), 0x3F)))
                    mstore8(add(ptr, 2), mload(and(shr( 6, input), 0x3F)))
                    mstore8(add(ptr, 3), mload(and(        input , 0x3F)))
                    
                    ptr := add(ptr, 4) // Advance 4 bytes.
                    // prettier-ignore
                    if iszero(lt(ptr, end)) { break }
                }

                let r := mod(dataLength, 3)

                switch noPadding
                case 0 {
                    // Offset `ptr` and pad with '='. We can simply write over the end.
                    mstore8(sub(ptr, iszero(iszero(r))), 0x3d) // Pad at `ptr - 1` if `r > 0`.
                    mstore8(sub(ptr, shl(1, eq(r, 1))), 0x3d) // Pad at `ptr - 2` if `r == 1`.
                    // Write the length of the string.
                    mstore(result, encodedLength)
                }
                default {
                    // Write the length of the string.
                    mstore(result, sub(encodedLength, add(iszero(iszero(r)), eq(r, 1))))
                }

                // Allocate the memory for the string.
                // Add 31 and mask with `not(31)` to round the
                // free memory pointer up the next multiple of 32.
                mstore(0x40, and(add(end, 31), not(31)))
            }
        }
    }

    /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
    /// Equivalent to `encode(data, false, false)`.
    function encode(bytes memory data) internal pure returns (string memory result) {
        result = encode(data, false, false);
    }

    /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
    /// Equivalent to `encode(data, fileSafe, false)`.
    function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) {
        result = encode(data, fileSafe, false);
    }

    /// @dev Encodes base64 encoded `data`.
    ///
    /// Supports:
    /// - RFC 4648 (both standard and file-safe mode).
    /// - RFC 3501 (63: ',').
    ///
    /// Does not support:
    /// - Line breaks.
    ///
    /// Note: For performance reasons,
    /// this function will NOT revert on invalid `data` inputs.
    /// Outputs for invalid inputs will simply be undefined behaviour.
    /// It is the user's responsibility to ensure that the `data`
    /// is a valid base64 encoded string.
    function decode(string memory data) internal pure returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let dataLength := mload(data)

            if dataLength {
                let end := add(data, dataLength)
                let decodedLength := mul(shr(2, dataLength), 3)

                switch and(dataLength, 3)
                case 0 {
                    // If padded.
                    decodedLength := sub(
                        decodedLength,
                        add(eq(and(mload(end), 0xFF), 0x3d), eq(and(mload(end), 0xFFFF), 0x3d3d))
                    )
                }
                default {
                    // If non-padded.
                    decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))
                }

                result := mload(0x40)

                // Write the length of the string.
                mstore(result, decodedLength)

                // Skip the first slot, which stores the length.
                let ptr := add(result, 0x20)

                // Load the table into the scratch space.
                // Constants are optimized for smaller bytecode with zero gas overhead.
                // `m` also doubles as the mask of the upper 6 bits.
                let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc
                mstore(0x5b, m)
                mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)
                mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)

                // prettier-ignore
                for {} 1 {} {
                    // Read 4 bytes.
                    data := add(data, 4)
                    let input := mload(data)

                    // Write 3 bytes.
                    mstore(ptr, or(
                        and(m, mload(byte(28, input))),
                        shr(6, or(
                            and(m, mload(byte(29, input))),
                            shr(6, or(
                                and(m, mload(byte(30, input))),
                                shr(6, mload(byte(31, input)))
                            ))
                        ))
                    ))

                    ptr := add(ptr, 3)
                    
                    // prettier-ignore
                    if iszero(lt(data, end)) { break }
                }

                // Allocate the memory for the string.
                // Add 32 + 31 and mask with `not(31)` to round the
                // free memory pointer up the next multiple of 32.
                mstore(0x40, and(add(add(result, decodedLength), 63), not(31)))

                // Restore the zero slot.
                mstore(0x60, 0)
            }
        }
    }
}

File 7 of 9 : LibBit.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for bit twiddling operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)
/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)
library LibBit {
    /// @dev Find last set.
    /// Returns the index of the most significant bit of `x`,
    /// counting from the least significant bit position.
    /// If `x` is zero, returns 256.
    /// Equivalent to `log2(x)`, but without reverting for the zero case.
    function fls(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(8, iszero(x))

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

            // For the remaining 32 bits, use a De Bruijn lookup.
            x := shr(r, x)
            x := or(x, shr(1, x))
            x := or(x, shr(2, x))
            x := or(x, shr(4, x))
            x := or(x, shr(8, x))
            x := or(x, shr(16, x))

            // prettier-ignore
            r := or(r, byte(shr(251, mul(x, shl(224, 0x07c4acdd))),
                0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f))
        }
    }

    /// @dev Count leading zeros.
    /// Returns the number of zeros preceding the most significant one bit.
    /// If `x` is zero, returns 256.
    function clz(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            let t := add(iszero(x), 255)

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

            // For the remaining 32 bits, use a De Bruijn lookup.
            x := shr(r, x)
            x := or(x, shr(1, x))
            x := or(x, shr(2, x))
            x := or(x, shr(4, x))
            x := or(x, shr(8, x))
            x := or(x, shr(16, x))

            // prettier-ignore
            r := sub(t, or(r, byte(shr(251, mul(x, shl(224, 0x07c4acdd))),
                0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f)))
        }
    }

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

            // Isolate the least significant bit.
            x := and(x, add(not(x), 1))

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

            // For the remaining 32 bits, use a De Bruijn lookup.
            // prettier-ignore
            r := or(r, byte(shr(251, mul(shr(r, x), shl(224, 0x077cb531))), 
                0x00011c021d0e18031e16140f191104081f1b0d17151310071a0c12060b050a09))
        }
    }

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

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

File 8 of 9 : LibBitmap.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./LibBit.sol";

/// @notice Efficient bitmap library for mapping integers to single bit booleans.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol)
library LibBitmap {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

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

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

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

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

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

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

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

    /// @dev Flips the bit at `index` in `bitmap`.
    /// Returns the boolean result of the flipped bit.
    function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, shr(8, index))
            mstore(0x20, bitmap.slot)
            let storageSlot := keccak256(0x00, 0x40)
            let shift := and(index, 0xff)
            let storageValue := sload(storageSlot)

            let mask := shl(shift, 1)
            storageValue := xor(storageValue, mask)
            // It makes sense to return the `newIsSet`,
            // as it allow us to skip an additional warm `sload`,
            // and it costs minimal gas (about 15),
            // which may be optimized away if the returned value is unused.
            newIsSet := iszero(iszero(and(storageValue, mask)))
            sstore(storageSlot, storageValue)
        }
    }

    /// @dev Updates the bit at `index` in `bitmap` to `shouldSet`.
    function setTo(
        Bitmap storage bitmap,
        uint256 index,
        bool shouldSet
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, bitmap.slot)
            mstore(0x00, shr(8, index))
            let storageSlot := keccak256(0x00, 0x40)
            let storageValue := sload(storageSlot)
            let shift := and(index, 0xff)

            sstore(
                storageSlot,
                // Unsets the bit at `shift` via `and`, then sets its new value via `or`.
                or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))
            )
        }
    }

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

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

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

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

File 9 of 9 : SSTORE2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solady (https://github.com/vectorized/solmady/blob/main/src/utils/SSTORE2.sol)
/// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
library SSTORE2 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unable to deploy the storage contract.
    error DeploymentFailed();

    /// @dev The storage contract address is invalid.
    error InvalidPointer();

    /// @dev Attempt to read outside of the storage contract's bytecode bounds.
    error ReadOutOfBounds();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         WRITE LOGIC                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Writes `data` into the bytecode of a storage contract and returns its address.
    function write(bytes memory data) internal returns (address pointer) {
        // Note: The assembly block below does not expand the memory.
        /// @solidity memory-safe-assembly
        assembly {
            let originalDataLength := mload(data)

            // Add 1 to data size since we are prefixing it with a STOP opcode.
            let dataSize := add(originalDataLength, 1)

            /**
             * ------------------------------------------------------------------------------+
             * Opcode      | Mnemonic        | Stack                   | Memory              |
             * ------------------------------------------------------------------------------|
             * 61 codeSize | PUSH2 codeSize  | codeSize                |                     |
             * 80          | DUP1            | codeSize codeSize       |                     |
             * 60 0xa      | PUSH1 0xa       | 0xa codeSize codeSize   |                     |
             * 3D          | RETURNDATASIZE  | 0 0xa codeSize codeSize |                     |
             * 39          | CODECOPY        | codeSize                | [0..codeSize): code |
             * 3D          | RETURNDATASZIE  | 0 codeSize              | [0..codeSize): code |
             * F3          | RETURN          |                         | [0..codeSize): code |
             * 00          | STOP            |                         |                     |
             * ------------------------------------------------------------------------------+
             * @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called.
             * Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16.
             */
            mstore(
                data,
                or(
                    0x61000080600a3d393df300,
                    // Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2.
                    shl(0x40, dataSize)
                )
            )

            // Deploy a new contract with the generated creation code.
            pointer := create(0, add(data, 0x15), add(dataSize, 0xa))

            // If `pointer` is zero, revert.
            if iszero(pointer) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Restore original length of the variable size `data`.
            mstore(data, originalDataLength)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         READ LOGIC                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns all the `data` from the bytecode of the storage contract at `pointer`.
    function read(address pointer) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Offset all indices by 1 to skip the STOP opcode.
            let size := sub(pointerCodesize, 1)

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
            extcodecopy(pointer, add(data, 0x20), 1, size)
        }
    }

    /// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
    /// from the byte at `start`, to the end of the data stored.
    function read(address pointer, uint256 start) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // If `!(pointer.code.size > start)`, reverts.
            // This also handles the case where `start + 1` overflows.
            if iszero(gt(pointerCodesize, start)) {
                // Store the function selector of `ReadOutOfBounds()`.
                mstore(0x00, 0x84eb0dd1)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            let size := sub(pointerCodesize, add(start, 1))

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
            extcodecopy(pointer, add(data, 0x20), add(start, 1), size)
        }
    }

    /// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
    /// from the byte at `start`, to the byte at `end` (exclusive) of the data stored.
    function read(
        address pointer,
        uint256 start,
        uint256 end
    ) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // If `!(pointer.code.size > end) || (start > end)`, revert.
            // This also handles the cases where `end + 1` or `start + 1` overflow.
            if iszero(
                and(
                    gt(pointerCodesize, end), // Within bounds.
                    iszero(gt(start, end)) // Valid range.
                )
            ) {
                // Store the function selector of `ReadOutOfBounds()`.
                mstore(0x00, 0x84eb0dd1)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            let size := sub(end, start)

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot.
            extcodecopy(pointer, add(data, 0x20), add(start, 1), size)
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"tokenCollectionAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"CollectionZeroAddress","type":"error"},{"inputs":[],"name":"InvalidParams","type":"error"},{"inputs":[],"name":"LevelMinimumLowerThanExisting","type":"error"},{"inputs":[],"name":"MessageTooLong","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"OnlyForYou","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"SvgAlreadySet","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"},{"inputs":[],"name":"Unauthorized","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":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","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":"uint256","name":"tokenId","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","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":"DEFAULT_DESC","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NONON_MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burnToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"collectionAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"hasReceivedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"hasSentToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"hasToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"levels","outputs":[{"internalType":"uint256","name":"minimum","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"colorGradient","type":"string"},{"internalType":"uint16","name":"spriteIndex","type":"uint16"},{"internalType":"uint16","name":"spriteLength","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"messages","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"ordinalsFromRoles","outputs":[{"internalType":"uint8[]","name":"ordinals","type":"uint8[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","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":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipHandoverValidFor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"points","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":"collectionTokenStartId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"registerTokenMovement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"ordinals","type":"uint8[]"}],"name":"rolesFromOrdinals","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"baseImage","type":"bytes"}],"name":"setBaseSvgPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"defs","type":"bytes"}],"name":"setDefsSvgPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_message","type":"string"}],"name":"setMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"spriteImages","type":"bytes"}],"name":"setSpritesSvgPointer","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":"tokenMessage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"tokenPointsInRange","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"points","type":"uint256"}],"internalType":"struct NononFriendCard.TokenPoints[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"sent","type":"bool"}],"name":"tokenStatusMap","outputs":[{"internalType":"uint256[]","name":"received","type":"uint256[]"}],"stateMutability":"view","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":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]

60a06040523480156200001157600080fd5b506040516200448d3803806200448d833981016040819052620000349162000a30565b60408051808201825260118152701393d393d3881194925153910810d05491607a1b60208083019182528351808501909452600c84526b1393d393d397d1949251539160a21b90840152815191929162000091916002916200098a565b508051620000a79060039060208401906200098a565b5050600160005550620000ba336200094c565b606081811b6001600160601b03191660809081526040805160a081018252600080825282518084018452600680825265414e47454c5360d01b6020808401919091528085019283528551808701875291825265677261642d3160d01b828201529484015294820181905261012093820193909352600d8054600181018255935280516000805160206200444d83398151915260049094029384019081559351805191949362000180936000805160206200446d833981519152909101929101906200098a565b50604082015180516200019e9160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a081018252600a808252825180840184529081526941524348414e47454c5360b01b60208281019190915280830191825283518085018552600681526533b930b2169960d11b81830152938301939093526101209382019390935261028c93810193909352600d8054600181018255600091909152835160049091026000805160206200444d833981519152810191825592518051919362000291936000805160206200446d833981519152909101929101906200098a565b5060408201518051620002af9160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a0810182526032815281518083018352600e81526d5052494e434950414c495449455360901b602082810191909152808301918252835180850185526006815265677261642d3360d01b81830152938301939093526103ac938201939093526102f693810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620003a6936000805160206200446d833981519152909101929101906200098a565b5060408201518051620003c49160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a081018252609681528151808301835260078152665649525455455360c81b60208281019190915280830191825283518085018552600681526519dc98590b4d60d21b81830152938301939093526106a29382019390935261028693810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620004b4936000805160206200446d833981519152909101929101906200098a565b5060408201518051620004d29160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a0810182526101f48152815180830183526009815268444f4d494e494f4e5360b81b602082810191909152808301918252835180850185526006815265677261642d3560d01b8183015293830193909352610928938201939093526103d893810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620005c5936000805160206200446d833981519152909101929101906200098a565b5060408201518051620005e39160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a0810182526105dc81528151808301835260078152665448524f4e455360c81b60208281019190915280830191825283518085018552600681526533b930b2169b60d11b8183015293830193909352610d009382019390935261033193810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620006d4936000805160206200446d833981519152909101929101906200098a565b5060408201518051620006f29160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a081018252610dac8152815180830183526008815267434845525542494d60c01b602082810191909152808301918252835180850185526006815265677261642d3760d01b8183015293830193909352611031938201939093526102f693810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620007e4936000805160206200446d833981519152909101929101906200098a565b5060408201518051620008029160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a081018252611d4c8152815180830183526008815267534552415048494d60c01b6020828101919091528083019182528351808501855260068152650cee4c2c85a760d31b8183015293830193909352611327938201939093526102c593810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620008f4936000805160206200446d833981519152909101929101906200098a565b5060408201518051620009129160028401916020909101906200098a565b5060608201516003909101805460809093015161ffff908116620100000263ffffffff199094169216919091179190911790555062000a9d565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b828054620009989062000a60565b90600052602060002090601f016020900481019282620009bc576000855562000a07565b82601f10620009d757805160ff191683800117855562000a07565b8280016001018555821562000a07579182015b8281111562000a07578251825591602001919060010190620009ea565b5062000a1592915062000a19565b5090565b5b8082111562000a15576000815560010162000a1a565b60006020828403121562000a42578081fd5b81516001600160a01b038116811462000a59578182fd5b9392505050565b600181811c9082168062000a7557607f821691505b6020821081141562000a9757634e487b7160e01b600052602260045260246000fd5b50919050565b60805160601c61396e62000adf6000396000818161068e01528181610d1e0152818161141901528181611512015281816118170152612804015261396e6000f3fe6080604052600436106102e45760003560e01c8063648345c811610190578063b6ee607a116100dc578063e4b7baeb11610095578063eacd39221161006f578063eacd39221461094d578063f04e283e1461096d578063f2fde38b14610980578063fee81cf41461099357600080fd5b8063e4b7baeb146108b7578063e6771966146108d7578063e985e9c51461090457600080fd5b8063b6ee607a14610804578063b88d4fde14610824578063b8ea8c6f14610844578063c0a4b93914610859578063c87b56dd14610879578063d7533f021461089957600080fd5b80637b47ec1a116101495780639799b4e7116101235780639799b4e7146107735780639bb0f59914610793578063a22cb465146107b3578063b2596a67146107d357600080fd5b80637b47ec1a146107255780638da5cb5b1461074557806395d89b411461075e57600080fd5b8063648345c81461065c5780636aa003711461067c57806370a08231146106b0578063715018a6146106d05780637359e41f146106d8578063755edd171461070557600080fd5b806323b872dd1161024f57806342ec38e2116102085780634a4ee7b1116101e25780634a4ee7b1146105ea578063514e62fc146105fd57806354d1f13d146106345780636352211e1461063c57600080fd5b806342ec38e2146105875780634812e9a6146105b4578063498a3596146105d457600080fd5b806323b872dd146104ce57806325692962146104ee5780632de94807146104f6578063372b67de14610527578063417011dc1461054757806342842e0e1461056757600080fd5b806316ab3342116102a157806316ab3342146103e857806318160ddd14610415578063183a4f6e1461043257806318821400146104455780631c10893f146104845780631cd64df41461049757600080fd5b806301ffc9a7146102e957806306fdde031461031e578063081812fc14610340578063095ea7b3146103785780630d80fefd1461039a57806313a661ed146103ba575b600080fd5b3480156102f557600080fd5b50610309610304366004613076565b6109c4565b60405190151581526020015b60405180910390f35b34801561032a57600080fd5b50610333610a16565b604051610315919061375b565b34801561034c57600080fd5b5061036061035b3660046130e1565b610aa8565b6040516001600160a01b039091168152602001610315565b34801561038457600080fd5b50610398610393366004612f94565b610aec565b005b3480156103a657600080fd5b506103336103b53660046130e1565b610b8c565b3480156103c657600080fd5b506103da6103d5366004612fbd565b610c26565b604051908152602001610315565b3480156103f457600080fd5b50610408610403366004613188565b610c59565b604051610315919061367a565b34801561042157600080fd5b5060015460005403600019016103da565b6103986104403660046130e1565b610eaf565b34801561045157600080fd5b506103336040518060400160405280601381526020017202727a727a710232924a2a7221021a0a9221d1606d1b81525081565b610398610492366004612f94565b610ebc565b3480156104a357600080fd5b506103096104b2366004612f94565b60609190911b638b78c6d8176000908152602090205481161490565b3480156104da57600080fd5b506103986104e9366004612e78565b610ee5565b61039861107b565b34801561050257600080fd5b506103da610511366004612e2c565b60601b638b78c6d8176000908152602090205490565b34801561053357600080fd5b506103986105423660046130ae565b6110cc565b34801561055357600080fd5b506103986105623660046130ae565b611144565b34801561057357600080fd5b50610398610582366004612e78565b6111bc565b34801561059357600080fd5b506103da6105a2366004612e2c565b600e6020526000908152604090205481565b3480156105c057600080fd5b506103096105cf366004612f94565b6111dc565b3480156105e057600080fd5b506103da61138881565b6103986105f8366004612f94565b611213565b34801561060957600080fd5b50610309610618366004612f94565b60609190911b638b78c6d8176000908152602090205416151590565b610398611238565b34801561064857600080fd5b506103606106573660046130e1565b611275565b34801561066857600080fd5b50610398610677366004613111565b611280565b34801561068857600080fd5b506103607f000000000000000000000000000000000000000000000000000000000000000081565b3480156106bc57600080fd5b506103da6106cb366004612e2c565b611325565b610398611374565b3480156106e457600080fd5b506106f86106f33660046130e1565b6113c2565b6040516103159190613720565b34801561071157600080fd5b50610398610720366004612e2c565b61140e565b34801561073157600080fd5b506103986107403660046130e1565b6114b5565b34801561075157600080fd5b50638b78c6d81954610360565b34801561076a57600080fd5b506103336114f1565b34801561077f57600080fd5b506103da61078e3660046130e1565b611500565b34801561079f57600080fd5b506103096107ae366004612e2c565b611609565b3480156107bf57600080fd5b506103986107ce366004612f5a565b61161c565b3480156107df57600080fd5b506107f36107ee3660046130e1565b6116b2565b60405161031595949392919061376e565b34801561081057600080fd5b5061039861081f366004612f19565b61180c565b34801561083057600080fd5b5061039861083f366004612eb3565b611912565b34801561085057600080fd5b5061033361195c565b34801561086557600080fd5b506103986108743660046130ae565b611978565b34801561088557600080fd5b506103336108943660046130e1565b6119f0565b3480156108a557600080fd5b506040516202a3008152602001610315565b3480156108c357600080fd5b506103336108d23660046130e1565b611b56565b3480156108e357600080fd5b506108f76108f2366004612f5a565b611c2a565b60405161031591906136dc565b34801561091057600080fd5b5061030961091f366004612e46565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b34801561095957600080fd5b50610309610968366004612f94565b611d30565b61039861097b366004612e2c565b611d65565b61039861098e366004612e2c565b611de7565b34801561099f57600080fd5b506103da6109ae366004612e2c565b60601b63389a75e1176000908152602090205490565b60006301ffc9a760e01b6001600160e01b0319831614806109f557506380ac58cd60e01b6001600160e01b03198316145b80610a105750635b5e139f60e01b6001600160e01b03198316145b92915050565b606060028054610a2590613865565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5190613865565b8015610a9e5780601f10610a7357610100808354040283529160200191610a9e565b820191906000526020600020905b815481529060010190602001808311610a8157829003601f168201915b5050505050905090565b6000610ab382611e4e565b610ad0576040516333d1c03960e21b815260040160405180910390fd5b506000908152600660205260409020546001600160a01b031690565b6000610af782611275565b9050336001600160a01b03821614610b3057610b13813361091f565b610b30576040516367d9dca160e11b815260040160405180910390fd5b60008281526006602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600f6020526000908152604090208054610ba590613865565b80601f0160208091040260200160405190810160405280929190818152602001828054610bd190613865565b8015610c1e5780601f10610bf357610100808354040283529160200191610c1e565b820191906000526020600020905b815481529060010190602001808311610c0157829003601f168201915b505050505081565b600060208201825160051b81015b808214610c5257600160ff8351161b83179250602082019150610c34565b5050919050565b606082821015610c7c57604051635435b28960e11b815260040160405180910390fd5b6000610c888484613822565b610c939060016137eb565b67ffffffffffffffff811115610cb957634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610d1757816020015b610d0460405180606001604052806000815260200160006001600160a01b03168152602001600081525090565b815260200190600190039081610cd75790505b50905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7557600080fd5b505afa158015610d89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dad91906130f9565b610db89060016137eb565b90506000855b858111610ea457610dce81611e4e565b15610e94576000610dde82611275565b6001600160a01b038116600090815260096020526040812091925090610e0690600187611e83565b6001600160a01b0383166000908152600860205260409020610e2a90600188611e83565b610e3491906137eb565b90506040518060600160405280848152602001836001600160a01b0316815260200182815250868581518110610e7a57634e487b7160e01b600052603260045260246000fd5b602002602001018190525083610e8f9061389a565b935050505b610e9d8161389a565b9050610dbe565b509195945050505050565b610eb93382611f26565b50565b638b78c6d819543314610ed7576382b429006000526004601cfd5b610ee18282611f77565b5050565b6000610ef082611fc3565b9050836001600160a01b0316816001600160a01b031614610f235760405162a1148160e81b815260040160405180910390fd5b60008281526006602052604090208054610f4f8187335b6001600160a01b039081169116811491141790565b610f7a57610f5d863361091f565b610f7a57604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b038516610fa157604051633a954ecd60e21b815260040160405180910390fd5b610fae868686600161202c565b8015610fb957600082555b6001600160a01b038681166000908152600560205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260046020526040902055600160e11b831661104457600184016000818152600460205260409020546110425760005481146110425760008181526004602052604090208490555b505b83856001600160a01b0316876001600160a01b03166000805160206138f883398151915260405160405180910390a4505050505050565b60006202a30067ffffffffffffffff164201905063389a75e13360601b1760005280602060002055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b638b78c6d8195433146110e7576382b429006000526004601cfd5b600c54600160a01b900460ff1615611112576040516327ec863960e01b815260040160405180910390fd5b61111b8161206a565b600c80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b638b78c6d81954331461115f576382b429006000526004601cfd5b600a54600160a01b900460ff161561118a576040516327ec863960e01b815260040160405180910390fd5b6111938161206a565b600a80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b6111d783838360405180602001604052806000815250611912565b505050565b6001600160a01b03821660009081526008602081815260408084209285901c845291905281205460ff83161c6001165b9392505050565b638b78c6d81954331461122e576382b429006000526004601cfd5b610ee18282611f26565b63389a75e13360601b176000526000602060002055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6000610a1082611fc3565b3361128a84611275565b6001600160a01b0316146112b0576040516282b42960e81b815260040160405180910390fd5b6101008111156112d3576040516347e8b47560e11b815260040160405180910390fd5b6000838152600f602052604090206112ec908383612d0c565b506040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1505050565b60006001600160a01b03821661134e576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526005602052604090205467ffffffffffffffff1690565b638b78c6d81954331461138f576382b429006000526004601cfd5b6000337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36000638b78c6d81955565b606060206040510160005b8082526001841660051b820191508360011c9350836113eb576113f3565b6001016113cd565b5060405191508060405260208201810360051c825250919050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611456576040516282b42960e81b815260040160405180910390fd5b600080546001600160a01b0383168252600e602052604090912081905561147e8260016120ac565b6040518181527f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a16119060200160405180910390a15050565b600e60006114c283611275565b6001600160a01b03166001600160a01b0316815260200190815260200160002060009055610eb981600161218c565b606060038054610a2590613865565b60008061150c83611275565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561156957600080fd5b505afa15801561157d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a191906130f9565b6115ac9060016137eb565b6001600160a01b03831660009081526009602052604090209091506115d390600183611e83565b6001600160a01b03831660009081526008602052604090206115f790600184611e83565b61160191906137eb565b949350505050565b60008061161583611325565b1192915050565b6001600160a01b0382163314156116465760405163b06307db60e01b815260040160405180910390fd5b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600d81815481106116c257600080fd5b600091825260209091206004909102018054600182018054919350906116e790613865565b80601f016020809104026020016040519081016040528092919081815260200182805461171390613865565b80156117605780601f1061173557610100808354040283529160200191611760565b820191906000526020600020905b81548152906001019060200180831161174357829003601f168201915b50505050509080600201805461177590613865565b80601f01602080910402602001604051908101604052809291908181526020018280546117a190613865565b80156117ee5780601f106117c3576101008083540402835291602001916117ee565b820191906000526020600020905b8154815290600101906020018083116117d157829003601f168201915b5050506003909301549192505061ffff808216916201000090041685565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611854576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0384161561189f57836001600160a01b0316836001600160a01b03161461189f576001600160a01b038416600090815260096020526040902061189f9083836122cb565b6001600160a01b038316156118d1576001600160a01b03831660009081526008602052604090206118d19083836122cb565b604080516001815260001960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c910160405180910390a150505050565b61191d848484610ee5565b6001600160a01b0383163b156119565761193984848484612348565b611956576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b6040518060600160405280602181526020016139186021913981565b638b78c6d819543314611993576382b429006000526004601cfd5b600b54600160a01b900460ff16156119be576040516327ec863960e01b815260040160405180910390fd5b6119c78161206a565b600b80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b60606119fb82611e4e565b611a1857604051630a14c4b560e41b815260040160405180910390fd5b6000611a2383611500565b90506000611a308261243f565b90506000611a3d85611b56565b905060006040518060400160405280601d81526020017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815250905080611b2b6040518060400160405280601381526020017202727a727a710232924a2a7221021a0a9221d1606d1b8152508560000151604051602001611abf9291906131f1565b60405160208183030381529060405284611adc87608001516128f3565b611ae5896128f3565b8860000151611b028a602001518b604001518c606001518c612935565b604051602001611b1796959493929190613220565b604051602081830303815290604052612a12565b604051602001611b3c9291906131f1565b604051602081830303815290604052945050505050919050565b6000818152600f6020526040812080546060929190611b7490613865565b80601f0160208091040260200160405190810160405280929190818152602001828054611ba090613865565b8015611bed5780601f10611bc257610100808354040283529160200191611bed565b820191906000526020600020905b815481529060010190602001808311611bd057829003601f168201915b50505050509050600081511115611c045792915050565b604051806060016040528060218152602001613918602191399392505050565b50919050565b606060136000611c3b8260016137eb565b67ffffffffffffffff811115611c6157634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611c8a578160200160208202803683370190505b50905060005b828111611d275784611cc5576001600160a01b0386166000908152600860209081526040808320848452909152902054611cea565b6001600160a01b03861660009081526009602090815260408083208484529091529020545b828281518110611d0a57634e487b7160e01b600052603260045260246000fd5b602090810291909101015280611d1f8161389a565b915050611c90565b50949350505050565b6001600160a01b0382166000908152600960209081526040808320600885901c845290915281205460ff83161c60011661120c565b638b78c6d819543314611d80576382b429006000526004601cfd5b8060601b60601c905063389a75e18160601b1760005260206000208054421115611db257636f5e88186000526004601cfd5b600081555080337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b638b78c6d819543314611e02576382b429006000526004601cfd5b6001600160a01b031680611e1e57637448fbae6000526004601cfd5b80337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b600081600111158015611e62575060005482105b8015610a10575050600090815260046020526040902054600160e01b161590565b6000600883901c60ff841661010184820110611ef957600082815260208790526040902054611eb390821c612a20565b930160ff8116939250600182019160009160081c015b808314611ef757600083815260208890526040902054611ee890612a20565b84019350826001019250611ec9565b505b600082815260208790526040902054611f1a90821c6101008690031b612a20565b90920195945050505050565b638b78c6d88260601b176000526020600020805482811681189050808255808460601b60601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a350505050565b638b78c6d88260601b17600052602060002081815417808255808460601b60601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a350505050565b600081806001116120135760005481101561201357600081815260046020526040902054600160e01b8116612011575b8061120c575060001901600081815260046020526040902054611ff3565b505b604051636f96cda160e11b815260040160405180910390fd5b6001600160a01b0384161580159061204c57506001600160a01b03831615155b1561195657604051632f65177960e21b815260040160405180910390fd5b60008151600181018060401b6a61000080600a3d393df300178452600a8101601585016000f0925050816120a65763301164256000526004601cfd5b90915290565b600054816120cd5760405163b562e8dd60e01b815260040160405180910390fd5b6120da600084838561202c565b6001600160a01b03831660008181526005602090815260408083208054680100000000000000018802019055848352600490915281206001851460e11b4260a01b178317905582840190839083906000805160206138f88339815191528180a4600183015b81811461216557808360006000805160206138f8833981519152600080a460010161213f565b508161218357604051622e076360e81b815260040160405180910390fd5b60005550505050565b600061219783611fc3565b9050806000806121b586600090815260066020526040902080549091565b9150915084156121f5576121ca818433610f3a565b6121f5576121d8833361091f565b6121f557604051632ce44b5f60e11b815260040160405180910390fd5b61220383600088600161202c565b801561220e57600082555b6001600160a01b038316600081815260056020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b17600360e01b17600087815260046020526040902055600160e11b841661229557600186016000818152600460205260409020546122935760005481146122935760008181526004602052604090208590555b505b60405186906000906001600160a01b038616906000805160206138f8833981519152908390a45050600180548101905550505050565b60001960ff8316846020528360081c6000526101018382011061232d576000805160408220805485851b1790559390910160ff811693600181019160081c015b80821461232857816000528360406000205560018201915061230b565b506000525b60406000208284610100031c821b8154178155505050505050565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a029061237d90339089908890889060040161363d565b602060405180830381600087803b15801561239757600080fd5b505af19250505080156123c7575060408051601f3d908101601f191682019092526123c491810190613092565b60015b612422573d8080156123f5576040519150601f19603f3d011682016040523d82523d6000602084013e6123fa565b606091505b50805161241a576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b6124796040518060a001604052806060815260200160608152602001600061ffff168152602001600061ffff168152602001600081525090565b600d545b8015611c24576000600d612492600184613822565b815481106124b057634e487b7160e01b600052603260045260246000fd5b90600052602060002090600402016040518060a0016040529081600082015481526020016001820180546124e390613865565b80601f016020809104026020016040519081016040528092919081815260200182805461250f90613865565b801561255c5780601f106125315761010080835404028352916020019161255c565b820191906000526020600020905b81548152906001019060200180831161253f57829003601f168201915b5050505050815260200160028201805461257590613865565b80601f01602080910402602001604051908101604052809291908181526020018280546125a190613865565b80156125ee5780601f106125c3576101008083540402835291602001916125ee565b820191906000526020600020905b8154815290600101906020018083116125d157829003601f168201915b50505091835250506003919091015461ffff80821660208401526201000090910416604090910152805190915084106128e957600d54821015612800576000600d838154811061264e57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600402016040518060a00160405290816000820154815260200160018201805461268190613865565b80601f01602080910402602001604051908101604052809291908181526020018280546126ad90613865565b80156126fa5780601f106126cf576101008083540402835291602001916126fa565b820191906000526020600020905b8154815290600101906020018083116126dd57829003601f168201915b5050505050815260200160028201805461271390613865565b80601f016020809104026020016040519081016040528092919081815260200182805461273f90613865565b801561278c5780601f106127615761010080835404028352916020019161278c565b820191906000526020600020905b81548152906001019060200180831161276f57829003601f168201915b50505091835250506003919091015461ffff808216602080850191909152620100009092048116604093840152825160a08101845286830151815286840151928101929092526060808701518216938301939093526080958601511691810191909152905192810192909252509392505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561285b57600080fd5b505afa15801561286f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289391906130f9565b61289e906002613803565b90506040518060a001604052808360200151815260200183604001518152602001836060015161ffff168152602001836080015161ffff168152602001828152509350505050919050565b506000190161247d565b604080516080019081905280825b600183039250600a81066030018353600a90048061291e57612923565b612901565b50819003601f19909101908152919050565b60408051808201909152601a81527f646174613a696d6167652f7376672b786d6c3b6261736536342c0000000000006020820152600a5460609190600090612985906001600160a01b0316612ad0565b600c549091506000906129a0906001600160a01b0316612ad0565b600b549091506000906129bb906001600160a01b0316612ad0565b9050836129e48a856129ce868d8d612b1a565b8a86604051602001611b17959493929190613396565b6040516020016129f59291906131f1565b604051602081830303815290604052945050505050949350505050565b6060610a1082600080612c03565b7f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f5555555555555555555555555555555555555555555555555555555555555555600183901c168203600281901c7f3333333333333333333333333333333333333333333333333333333333333333908116911601600481901c01167f01010101010101010101010101010101010101010101010101010101010101010260f81c6000199190911460081b1790565b6060813b80612ae7576311052bb46000526004601cfd5b600181039050604051915061ffe0603f820116820160405280825260008160208401015280600160208401853c50919050565b606060008261ffff1667ffffffffffffffff811115612b4957634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015612b73576020820181803683370190505b50905060005b8151811015611d275785612b9161ffff8716836137eb565b81518110612baf57634e487b7160e01b600052603260045260246000fd5b602001015160f81c60f81b828281518110612bda57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535080612bfb8161389a565b915050612b79565b606083518015612d04576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c16518353603f81600c1c16516001840153603f8160061c16516002840153603f811651600384015350600482019150808210612cbc57612cc1565b612c73565b60038406868015612cdd57600182148215150185038752612cf5565b603d821515850353603d6001831460011b8503538487525b5050601f01601f191660405250505b509392505050565b828054612d1890613865565b90600052602060002090601f016020900481019282612d3a5760008555612d80565b82601f10612d535782800160ff19823516178555612d80565b82800160010185558215612d80579182015b82811115612d80578235825591602001919060010190612d65565b50612d8c929150612d90565b5090565b5b80821115612d8c5760008155600101612d91565b80356001600160a01b0381168114612dbc57600080fd5b919050565b600082601f830112612dd1578081fd5b813567ffffffffffffffff811115612deb57612deb6138cb565b612dfe601f8201601f19166020016137ba565b818152846020838601011115612e12578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215612e3d578081fd5b61120c82612da5565b60008060408385031215612e58578081fd5b612e6183612da5565b9150612e6f60208401612da5565b90509250929050565b600080600060608486031215612e8c578081fd5b612e9584612da5565b9250612ea360208501612da5565b9150604084013590509250925092565b60008060008060808587031215612ec8578081fd5b612ed185612da5565b9350612edf60208601612da5565b925060408501359150606085013567ffffffffffffffff811115612f01578182fd5b612f0d87828801612dc1565b91505092959194509250565b60008060008060808587031215612f2e578384fd5b612f3785612da5565b9350612f4560208601612da5565b93969395505050506040820135916060013590565b60008060408385031215612f6c578182fd5b612f7583612da5565b915060208301358015158114612f89578182fd5b809150509250929050565b60008060408385031215612fa6578182fd5b612faf83612da5565b946020939093013593505050565b60006020808385031215612fcf578182fd5b823567ffffffffffffffff80821115612fe6578384fd5b818501915085601f830112612ff9578384fd5b81358181111561300b5761300b6138cb565b8060051b915061301c8483016137ba565b8181528481019084860184860187018a1015613036578788fd5b8795505b83861015613069578035945060ff85168514613054578788fd5b8483526001959095019491860191860161303a565b5098975050505050505050565b600060208284031215613087578081fd5b813561120c816138e1565b6000602082840312156130a3578081fd5b815161120c816138e1565b6000602082840312156130bf578081fd5b813567ffffffffffffffff8111156130d5578182fd5b61160184828501612dc1565b6000602082840312156130f2578081fd5b5035919050565b60006020828403121561310a578081fd5b5051919050565b600080600060408486031215613125578081fd5b83359250602084013567ffffffffffffffff80821115613143578283fd5b818601915086601f830112613156578283fd5b813581811115613164578384fd5b876020828501011115613175578384fd5b6020830194508093505050509250925092565b6000806040838503121561319a578182fd5b50508035926020909101359150565b600081518084526131c1816020860160208601613839565b601f01601f19169290920160200192915050565b600081516131e7818560208601613839565b9290920192915050565b60008351613203818460208801613839565b835190830190613217818360208801613839565b01949350505050565b683d913730b6b2911d1160b91b81528651600090613245816009850160208c01613839565b61088b60f21b60099184019182018190526e113232b9b1b934b83a34b7b7111d1160891b600b830152885161328181601a850160208d01613839565b601a9201918201527f2261747472696275746573223a5b7b2274726169745f74797065223a22506f69601c82015270373a3991161136b0bc2fbb30b63ab2911d60791b603c82015286516132dc81604d840160208b01613839565b61338861337a61337461335f61334f61334961331561330f604d898b01016816113b30b63ab2911d60b91b815260090190565b8e6131d5565b7f7d2c207b2274726169745f74797065223a224c6576656c222c2276616c7565228152611d1160f11b602082015260220190565b8b6131d5565b63089f574b60e21b815260040190565b681134b6b0b3b2911d1160b91b815260090190565b876131d5565b61227d60f01b815260020190565b9a9950505050505050505050565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222066696c6c3d226e6f6e65222076696577426f783d2230203060208201527f20313038302031303830223e3c706174682066696c6c3d22726762612832353560408201527f2c3235352c3235352c30292220643d224d3020306831303830763130383048306060820152643d1110179f60d91b6080820152703c706174682066696c6c3d2275726c282360781b608582015260008651613468816096850160208b01613839565b7f292220643d224d32342034306131362031362030203020312031362d313668316096918401918201527f303030613136203136203020302031203136203136763931346131362031362060b68201527f30203020312d3136203136483131342e356132342032342030203020302d313760d68201527f2e3620372e376c2d35392036332e34613820382030203020312d31332e392d3560f682015269171a2b1a182d1110179f60b11b61011682015261363161361f6136196135fe6135f861353e61353861012088018e6131d5565b8c6131d5565b7f3c7465787420786d6c3a73706163653d227072657365727665222066696c6c3d81527f22233030394446352220666f6e742d66616d696c793d22436f7572696572222060208201527f666f6e742d73697a653d22323422206c65747465722d73706163696e673d223060408201527f656d22207374796c653d2277686974652d73706163653a707265223e3c74737060608201527530b7103c1e91189a1a11103c9e9118981a1a171c911f60511b608082015260960190565b896131d5565b6e1e17ba39b830b71f1e17ba32bc3a1f60891b8152600f0190565b866131d5565b651e17b9bb339f60d11b815260060190565b98975050505050505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613670908301846131a9565b9695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156136cf57815180518552868101516001600160a01b0316878601528501518585015260609093019290850190600101613697565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015613714578351835292840192918401916001016136f8565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561371457835160ff168352928401929184019160010161373c565b60208152600061120c60208301846131a9565b85815260a06020820152600061378760a08301876131a9565b828103604084015261379981876131a9565b91505061ffff80851660608401528084166080840152509695505050505050565b604051601f8201601f1916810167ffffffffffffffff811182821017156137e3576137e36138cb565b604052919050565b600082198211156137fe576137fe6138b5565b500190565b600081600019048311821515161561381d5761381d6138b5565b500290565b600082821015613834576138346138b5565b500390565b60005b8381101561385457818101518382015260200161383c565b838111156119565750506000910152565b600181811c9082168061387957607f821691505b60208210811415611c2457634e487b7160e01b600052602260045260246000fd5b60006000198214156138ae576138ae6138b5565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b031981168114610eb957600080fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef736861726520796f7572206d657373616765206174206e6f6e6f6e2e686f757365a26469706673582212206d095de219df15e46294140727498581aae7d369cc3a076e0839aca95b3c4fca64736f6c63430008040033d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb6000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca6

Deployed Bytecode

0x6080604052600436106102e45760003560e01c8063648345c811610190578063b6ee607a116100dc578063e4b7baeb11610095578063eacd39221161006f578063eacd39221461094d578063f04e283e1461096d578063f2fde38b14610980578063fee81cf41461099357600080fd5b8063e4b7baeb146108b7578063e6771966146108d7578063e985e9c51461090457600080fd5b8063b6ee607a14610804578063b88d4fde14610824578063b8ea8c6f14610844578063c0a4b93914610859578063c87b56dd14610879578063d7533f021461089957600080fd5b80637b47ec1a116101495780639799b4e7116101235780639799b4e7146107735780639bb0f59914610793578063a22cb465146107b3578063b2596a67146107d357600080fd5b80637b47ec1a146107255780638da5cb5b1461074557806395d89b411461075e57600080fd5b8063648345c81461065c5780636aa003711461067c57806370a08231146106b0578063715018a6146106d05780637359e41f146106d8578063755edd171461070557600080fd5b806323b872dd1161024f57806342ec38e2116102085780634a4ee7b1116101e25780634a4ee7b1146105ea578063514e62fc146105fd57806354d1f13d146106345780636352211e1461063c57600080fd5b806342ec38e2146105875780634812e9a6146105b4578063498a3596146105d457600080fd5b806323b872dd146104ce57806325692962146104ee5780632de94807146104f6578063372b67de14610527578063417011dc1461054757806342842e0e1461056757600080fd5b806316ab3342116102a157806316ab3342146103e857806318160ddd14610415578063183a4f6e1461043257806318821400146104455780631c10893f146104845780631cd64df41461049757600080fd5b806301ffc9a7146102e957806306fdde031461031e578063081812fc14610340578063095ea7b3146103785780630d80fefd1461039a57806313a661ed146103ba575b600080fd5b3480156102f557600080fd5b50610309610304366004613076565b6109c4565b60405190151581526020015b60405180910390f35b34801561032a57600080fd5b50610333610a16565b604051610315919061375b565b34801561034c57600080fd5b5061036061035b3660046130e1565b610aa8565b6040516001600160a01b039091168152602001610315565b34801561038457600080fd5b50610398610393366004612f94565b610aec565b005b3480156103a657600080fd5b506103336103b53660046130e1565b610b8c565b3480156103c657600080fd5b506103da6103d5366004612fbd565b610c26565b604051908152602001610315565b3480156103f457600080fd5b50610408610403366004613188565b610c59565b604051610315919061367a565b34801561042157600080fd5b5060015460005403600019016103da565b6103986104403660046130e1565b610eaf565b34801561045157600080fd5b506103336040518060400160405280601381526020017202727a727a710232924a2a7221021a0a9221d1606d1b81525081565b610398610492366004612f94565b610ebc565b3480156104a357600080fd5b506103096104b2366004612f94565b60609190911b638b78c6d8176000908152602090205481161490565b3480156104da57600080fd5b506103986104e9366004612e78565b610ee5565b61039861107b565b34801561050257600080fd5b506103da610511366004612e2c565b60601b638b78c6d8176000908152602090205490565b34801561053357600080fd5b506103986105423660046130ae565b6110cc565b34801561055357600080fd5b506103986105623660046130ae565b611144565b34801561057357600080fd5b50610398610582366004612e78565b6111bc565b34801561059357600080fd5b506103da6105a2366004612e2c565b600e6020526000908152604090205481565b3480156105c057600080fd5b506103096105cf366004612f94565b6111dc565b3480156105e057600080fd5b506103da61138881565b6103986105f8366004612f94565b611213565b34801561060957600080fd5b50610309610618366004612f94565b60609190911b638b78c6d8176000908152602090205416151590565b610398611238565b34801561064857600080fd5b506103606106573660046130e1565b611275565b34801561066857600080fd5b50610398610677366004613111565b611280565b34801561068857600080fd5b506103607f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca681565b3480156106bc57600080fd5b506103da6106cb366004612e2c565b611325565b610398611374565b3480156106e457600080fd5b506106f86106f33660046130e1565b6113c2565b6040516103159190613720565b34801561071157600080fd5b50610398610720366004612e2c565b61140e565b34801561073157600080fd5b506103986107403660046130e1565b6114b5565b34801561075157600080fd5b50638b78c6d81954610360565b34801561076a57600080fd5b506103336114f1565b34801561077f57600080fd5b506103da61078e3660046130e1565b611500565b34801561079f57600080fd5b506103096107ae366004612e2c565b611609565b3480156107bf57600080fd5b506103986107ce366004612f5a565b61161c565b3480156107df57600080fd5b506107f36107ee3660046130e1565b6116b2565b60405161031595949392919061376e565b34801561081057600080fd5b5061039861081f366004612f19565b61180c565b34801561083057600080fd5b5061039861083f366004612eb3565b611912565b34801561085057600080fd5b5061033361195c565b34801561086557600080fd5b506103986108743660046130ae565b611978565b34801561088557600080fd5b506103336108943660046130e1565b6119f0565b3480156108a557600080fd5b506040516202a3008152602001610315565b3480156108c357600080fd5b506103336108d23660046130e1565b611b56565b3480156108e357600080fd5b506108f76108f2366004612f5a565b611c2a565b60405161031591906136dc565b34801561091057600080fd5b5061030961091f366004612e46565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b34801561095957600080fd5b50610309610968366004612f94565b611d30565b61039861097b366004612e2c565b611d65565b61039861098e366004612e2c565b611de7565b34801561099f57600080fd5b506103da6109ae366004612e2c565b60601b63389a75e1176000908152602090205490565b60006301ffc9a760e01b6001600160e01b0319831614806109f557506380ac58cd60e01b6001600160e01b03198316145b80610a105750635b5e139f60e01b6001600160e01b03198316145b92915050565b606060028054610a2590613865565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5190613865565b8015610a9e5780601f10610a7357610100808354040283529160200191610a9e565b820191906000526020600020905b815481529060010190602001808311610a8157829003601f168201915b5050505050905090565b6000610ab382611e4e565b610ad0576040516333d1c03960e21b815260040160405180910390fd5b506000908152600660205260409020546001600160a01b031690565b6000610af782611275565b9050336001600160a01b03821614610b3057610b13813361091f565b610b30576040516367d9dca160e11b815260040160405180910390fd5b60008281526006602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600f6020526000908152604090208054610ba590613865565b80601f0160208091040260200160405190810160405280929190818152602001828054610bd190613865565b8015610c1e5780601f10610bf357610100808354040283529160200191610c1e565b820191906000526020600020905b815481529060010190602001808311610c0157829003601f168201915b505050505081565b600060208201825160051b81015b808214610c5257600160ff8351161b83179250602082019150610c34565b5050919050565b606082821015610c7c57604051635435b28960e11b815260040160405180910390fd5b6000610c888484613822565b610c939060016137eb565b67ffffffffffffffff811115610cb957634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610d1757816020015b610d0460405180606001604052806000815260200160006001600160a01b03168152602001600081525090565b815260200190600190039081610cd75790505b50905060007f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca66001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7557600080fd5b505afa158015610d89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dad91906130f9565b610db89060016137eb565b90506000855b858111610ea457610dce81611e4e565b15610e94576000610dde82611275565b6001600160a01b038116600090815260096020526040812091925090610e0690600187611e83565b6001600160a01b0383166000908152600860205260409020610e2a90600188611e83565b610e3491906137eb565b90506040518060600160405280848152602001836001600160a01b0316815260200182815250868581518110610e7a57634e487b7160e01b600052603260045260246000fd5b602002602001018190525083610e8f9061389a565b935050505b610e9d8161389a565b9050610dbe565b509195945050505050565b610eb93382611f26565b50565b638b78c6d819543314610ed7576382b429006000526004601cfd5b610ee18282611f77565b5050565b6000610ef082611fc3565b9050836001600160a01b0316816001600160a01b031614610f235760405162a1148160e81b815260040160405180910390fd5b60008281526006602052604090208054610f4f8187335b6001600160a01b039081169116811491141790565b610f7a57610f5d863361091f565b610f7a57604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b038516610fa157604051633a954ecd60e21b815260040160405180910390fd5b610fae868686600161202c565b8015610fb957600082555b6001600160a01b038681166000908152600560205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260046020526040902055600160e11b831661104457600184016000818152600460205260409020546110425760005481146110425760008181526004602052604090208490555b505b83856001600160a01b0316876001600160a01b03166000805160206138f883398151915260405160405180910390a4505050505050565b60006202a30067ffffffffffffffff164201905063389a75e13360601b1760005280602060002055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b638b78c6d8195433146110e7576382b429006000526004601cfd5b600c54600160a01b900460ff1615611112576040516327ec863960e01b815260040160405180910390fd5b61111b8161206a565b600c80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b638b78c6d81954331461115f576382b429006000526004601cfd5b600a54600160a01b900460ff161561118a576040516327ec863960e01b815260040160405180910390fd5b6111938161206a565b600a80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b6111d783838360405180602001604052806000815250611912565b505050565b6001600160a01b03821660009081526008602081815260408084209285901c845291905281205460ff83161c6001165b9392505050565b638b78c6d81954331461122e576382b429006000526004601cfd5b610ee18282611f26565b63389a75e13360601b176000526000602060002055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6000610a1082611fc3565b3361128a84611275565b6001600160a01b0316146112b0576040516282b42960e81b815260040160405180910390fd5b6101008111156112d3576040516347e8b47560e11b815260040160405180910390fd5b6000838152600f602052604090206112ec908383612d0c565b506040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1505050565b60006001600160a01b03821661134e576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526005602052604090205467ffffffffffffffff1690565b638b78c6d81954331461138f576382b429006000526004601cfd5b6000337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36000638b78c6d81955565b606060206040510160005b8082526001841660051b820191508360011c9350836113eb576113f3565b6001016113cd565b5060405191508060405260208201810360051c825250919050565b336001600160a01b037f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca61614611456576040516282b42960e81b815260040160405180910390fd5b600080546001600160a01b0383168252600e602052604090912081905561147e8260016120ac565b6040518181527f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a16119060200160405180910390a15050565b600e60006114c283611275565b6001600160a01b03166001600160a01b0316815260200190815260200160002060009055610eb981600161218c565b606060038054610a2590613865565b60008061150c83611275565b905060007f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca66001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561156957600080fd5b505afa15801561157d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a191906130f9565b6115ac9060016137eb565b6001600160a01b03831660009081526009602052604090209091506115d390600183611e83565b6001600160a01b03831660009081526008602052604090206115f790600184611e83565b61160191906137eb565b949350505050565b60008061161583611325565b1192915050565b6001600160a01b0382163314156116465760405163b06307db60e01b815260040160405180910390fd5b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600d81815481106116c257600080fd5b600091825260209091206004909102018054600182018054919350906116e790613865565b80601f016020809104026020016040519081016040528092919081815260200182805461171390613865565b80156117605780601f1061173557610100808354040283529160200191611760565b820191906000526020600020905b81548152906001019060200180831161174357829003601f168201915b50505050509080600201805461177590613865565b80601f01602080910402602001604051908101604052809291908181526020018280546117a190613865565b80156117ee5780601f106117c3576101008083540402835291602001916117ee565b820191906000526020600020905b8154815290600101906020018083116117d157829003601f168201915b5050506003909301549192505061ffff808216916201000090041685565b336001600160a01b037f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca61614611854576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0384161561189f57836001600160a01b0316836001600160a01b03161461189f576001600160a01b038416600090815260096020526040902061189f9083836122cb565b6001600160a01b038316156118d1576001600160a01b03831660009081526008602052604090206118d19083836122cb565b604080516001815260001960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c910160405180910390a150505050565b61191d848484610ee5565b6001600160a01b0383163b156119565761193984848484612348565b611956576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b6040518060600160405280602181526020016139186021913981565b638b78c6d819543314611993576382b429006000526004601cfd5b600b54600160a01b900460ff16156119be576040516327ec863960e01b815260040160405180910390fd5b6119c78161206a565b600b80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b60606119fb82611e4e565b611a1857604051630a14c4b560e41b815260040160405180910390fd5b6000611a2383611500565b90506000611a308261243f565b90506000611a3d85611b56565b905060006040518060400160405280601d81526020017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815250905080611b2b6040518060400160405280601381526020017202727a727a710232924a2a7221021a0a9221d1606d1b8152508560000151604051602001611abf9291906131f1565b60405160208183030381529060405284611adc87608001516128f3565b611ae5896128f3565b8860000151611b028a602001518b604001518c606001518c612935565b604051602001611b1796959493929190613220565b604051602081830303815290604052612a12565b604051602001611b3c9291906131f1565b604051602081830303815290604052945050505050919050565b6000818152600f6020526040812080546060929190611b7490613865565b80601f0160208091040260200160405190810160405280929190818152602001828054611ba090613865565b8015611bed5780601f10611bc257610100808354040283529160200191611bed565b820191906000526020600020905b815481529060010190602001808311611bd057829003601f168201915b50505050509050600081511115611c045792915050565b604051806060016040528060218152602001613918602191399392505050565b50919050565b606060136000611c3b8260016137eb565b67ffffffffffffffff811115611c6157634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611c8a578160200160208202803683370190505b50905060005b828111611d275784611cc5576001600160a01b0386166000908152600860209081526040808320848452909152902054611cea565b6001600160a01b03861660009081526009602090815260408083208484529091529020545b828281518110611d0a57634e487b7160e01b600052603260045260246000fd5b602090810291909101015280611d1f8161389a565b915050611c90565b50949350505050565b6001600160a01b0382166000908152600960209081526040808320600885901c845290915281205460ff83161c60011661120c565b638b78c6d819543314611d80576382b429006000526004601cfd5b8060601b60601c905063389a75e18160601b1760005260206000208054421115611db257636f5e88186000526004601cfd5b600081555080337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b638b78c6d819543314611e02576382b429006000526004601cfd5b6001600160a01b031680611e1e57637448fbae6000526004601cfd5b80337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b600081600111158015611e62575060005482105b8015610a10575050600090815260046020526040902054600160e01b161590565b6000600883901c60ff841661010184820110611ef957600082815260208790526040902054611eb390821c612a20565b930160ff8116939250600182019160009160081c015b808314611ef757600083815260208890526040902054611ee890612a20565b84019350826001019250611ec9565b505b600082815260208790526040902054611f1a90821c6101008690031b612a20565b90920195945050505050565b638b78c6d88260601b176000526020600020805482811681189050808255808460601b60601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a350505050565b638b78c6d88260601b17600052602060002081815417808255808460601b60601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a350505050565b600081806001116120135760005481101561201357600081815260046020526040902054600160e01b8116612011575b8061120c575060001901600081815260046020526040902054611ff3565b505b604051636f96cda160e11b815260040160405180910390fd5b6001600160a01b0384161580159061204c57506001600160a01b03831615155b1561195657604051632f65177960e21b815260040160405180910390fd5b60008151600181018060401b6a61000080600a3d393df300178452600a8101601585016000f0925050816120a65763301164256000526004601cfd5b90915290565b600054816120cd5760405163b562e8dd60e01b815260040160405180910390fd5b6120da600084838561202c565b6001600160a01b03831660008181526005602090815260408083208054680100000000000000018802019055848352600490915281206001851460e11b4260a01b178317905582840190839083906000805160206138f88339815191528180a4600183015b81811461216557808360006000805160206138f8833981519152600080a460010161213f565b508161218357604051622e076360e81b815260040160405180910390fd5b60005550505050565b600061219783611fc3565b9050806000806121b586600090815260066020526040902080549091565b9150915084156121f5576121ca818433610f3a565b6121f5576121d8833361091f565b6121f557604051632ce44b5f60e11b815260040160405180910390fd5b61220383600088600161202c565b801561220e57600082555b6001600160a01b038316600081815260056020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b17600360e01b17600087815260046020526040902055600160e11b841661229557600186016000818152600460205260409020546122935760005481146122935760008181526004602052604090208590555b505b60405186906000906001600160a01b038616906000805160206138f8833981519152908390a45050600180548101905550505050565b60001960ff8316846020528360081c6000526101018382011061232d576000805160408220805485851b1790559390910160ff811693600181019160081c015b80821461232857816000528360406000205560018201915061230b565b506000525b60406000208284610100031c821b8154178155505050505050565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a029061237d90339089908890889060040161363d565b602060405180830381600087803b15801561239757600080fd5b505af19250505080156123c7575060408051601f3d908101601f191682019092526123c491810190613092565b60015b612422573d8080156123f5576040519150601f19603f3d011682016040523d82523d6000602084013e6123fa565b606091505b50805161241a576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b6124796040518060a001604052806060815260200160608152602001600061ffff168152602001600061ffff168152602001600081525090565b600d545b8015611c24576000600d612492600184613822565b815481106124b057634e487b7160e01b600052603260045260246000fd5b90600052602060002090600402016040518060a0016040529081600082015481526020016001820180546124e390613865565b80601f016020809104026020016040519081016040528092919081815260200182805461250f90613865565b801561255c5780601f106125315761010080835404028352916020019161255c565b820191906000526020600020905b81548152906001019060200180831161253f57829003601f168201915b5050505050815260200160028201805461257590613865565b80601f01602080910402602001604051908101604052809291908181526020018280546125a190613865565b80156125ee5780601f106125c3576101008083540402835291602001916125ee565b820191906000526020600020905b8154815290600101906020018083116125d157829003601f168201915b50505091835250506003919091015461ffff80821660208401526201000090910416604090910152805190915084106128e957600d54821015612800576000600d838154811061264e57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600402016040518060a00160405290816000820154815260200160018201805461268190613865565b80601f01602080910402602001604051908101604052809291908181526020018280546126ad90613865565b80156126fa5780601f106126cf576101008083540402835291602001916126fa565b820191906000526020600020905b8154815290600101906020018083116126dd57829003601f168201915b5050505050815260200160028201805461271390613865565b80601f016020809104026020016040519081016040528092919081815260200182805461273f90613865565b801561278c5780601f106127615761010080835404028352916020019161278c565b820191906000526020600020905b81548152906001019060200180831161276f57829003601f168201915b50505091835250506003919091015461ffff808216602080850191909152620100009092048116604093840152825160a08101845286830151815286840151928101929092526060808701518216938301939093526080958601511691810191909152905192810192909252509392505050565b60007f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca66001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561285b57600080fd5b505afa15801561286f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289391906130f9565b61289e906002613803565b90506040518060a001604052808360200151815260200183604001518152602001836060015161ffff168152602001836080015161ffff168152602001828152509350505050919050565b506000190161247d565b604080516080019081905280825b600183039250600a81066030018353600a90048061291e57612923565b612901565b50819003601f19909101908152919050565b60408051808201909152601a81527f646174613a696d6167652f7376672b786d6c3b6261736536342c0000000000006020820152600a5460609190600090612985906001600160a01b0316612ad0565b600c549091506000906129a0906001600160a01b0316612ad0565b600b549091506000906129bb906001600160a01b0316612ad0565b9050836129e48a856129ce868d8d612b1a565b8a86604051602001611b17959493929190613396565b6040516020016129f59291906131f1565b604051602081830303815290604052945050505050949350505050565b6060610a1082600080612c03565b7f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f5555555555555555555555555555555555555555555555555555555555555555600183901c168203600281901c7f3333333333333333333333333333333333333333333333333333333333333333908116911601600481901c01167f01010101010101010101010101010101010101010101010101010101010101010260f81c6000199190911460081b1790565b6060813b80612ae7576311052bb46000526004601cfd5b600181039050604051915061ffe0603f820116820160405280825260008160208401015280600160208401853c50919050565b606060008261ffff1667ffffffffffffffff811115612b4957634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015612b73576020820181803683370190505b50905060005b8151811015611d275785612b9161ffff8716836137eb565b81518110612baf57634e487b7160e01b600052603260045260246000fd5b602001015160f81c60f81b828281518110612bda57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535080612bfb8161389a565b915050612b79565b606083518015612d04576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c16518353603f81600c1c16516001840153603f8160061c16516002840153603f811651600384015350600482019150808210612cbc57612cc1565b612c73565b60038406868015612cdd57600182148215150185038752612cf5565b603d821515850353603d6001831460011b8503538487525b5050601f01601f191660405250505b509392505050565b828054612d1890613865565b90600052602060002090601f016020900481019282612d3a5760008555612d80565b82601f10612d535782800160ff19823516178555612d80565b82800160010185558215612d80579182015b82811115612d80578235825591602001919060010190612d65565b50612d8c929150612d90565b5090565b5b80821115612d8c5760008155600101612d91565b80356001600160a01b0381168114612dbc57600080fd5b919050565b600082601f830112612dd1578081fd5b813567ffffffffffffffff811115612deb57612deb6138cb565b612dfe601f8201601f19166020016137ba565b818152846020838601011115612e12578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215612e3d578081fd5b61120c82612da5565b60008060408385031215612e58578081fd5b612e6183612da5565b9150612e6f60208401612da5565b90509250929050565b600080600060608486031215612e8c578081fd5b612e9584612da5565b9250612ea360208501612da5565b9150604084013590509250925092565b60008060008060808587031215612ec8578081fd5b612ed185612da5565b9350612edf60208601612da5565b925060408501359150606085013567ffffffffffffffff811115612f01578182fd5b612f0d87828801612dc1565b91505092959194509250565b60008060008060808587031215612f2e578384fd5b612f3785612da5565b9350612f4560208601612da5565b93969395505050506040820135916060013590565b60008060408385031215612f6c578182fd5b612f7583612da5565b915060208301358015158114612f89578182fd5b809150509250929050565b60008060408385031215612fa6578182fd5b612faf83612da5565b946020939093013593505050565b60006020808385031215612fcf578182fd5b823567ffffffffffffffff80821115612fe6578384fd5b818501915085601f830112612ff9578384fd5b81358181111561300b5761300b6138cb565b8060051b915061301c8483016137ba565b8181528481019084860184860187018a1015613036578788fd5b8795505b83861015613069578035945060ff85168514613054578788fd5b8483526001959095019491860191860161303a565b5098975050505050505050565b600060208284031215613087578081fd5b813561120c816138e1565b6000602082840312156130a3578081fd5b815161120c816138e1565b6000602082840312156130bf578081fd5b813567ffffffffffffffff8111156130d5578182fd5b61160184828501612dc1565b6000602082840312156130f2578081fd5b5035919050565b60006020828403121561310a578081fd5b5051919050565b600080600060408486031215613125578081fd5b83359250602084013567ffffffffffffffff80821115613143578283fd5b818601915086601f830112613156578283fd5b813581811115613164578384fd5b876020828501011115613175578384fd5b6020830194508093505050509250925092565b6000806040838503121561319a578182fd5b50508035926020909101359150565b600081518084526131c1816020860160208601613839565b601f01601f19169290920160200192915050565b600081516131e7818560208601613839565b9290920192915050565b60008351613203818460208801613839565b835190830190613217818360208801613839565b01949350505050565b683d913730b6b2911d1160b91b81528651600090613245816009850160208c01613839565b61088b60f21b60099184019182018190526e113232b9b1b934b83a34b7b7111d1160891b600b830152885161328181601a850160208d01613839565b601a9201918201527f2261747472696275746573223a5b7b2274726169745f74797065223a22506f69601c82015270373a3991161136b0bc2fbb30b63ab2911d60791b603c82015286516132dc81604d840160208b01613839565b61338861337a61337461335f61334f61334961331561330f604d898b01016816113b30b63ab2911d60b91b815260090190565b8e6131d5565b7f7d2c207b2274726169745f74797065223a224c6576656c222c2276616c7565228152611d1160f11b602082015260220190565b8b6131d5565b63089f574b60e21b815260040190565b681134b6b0b3b2911d1160b91b815260090190565b876131d5565b61227d60f01b815260020190565b9a9950505050505050505050565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222066696c6c3d226e6f6e65222076696577426f783d2230203060208201527f20313038302031303830223e3c706174682066696c6c3d22726762612832353560408201527f2c3235352c3235352c30292220643d224d3020306831303830763130383048306060820152643d1110179f60d91b6080820152703c706174682066696c6c3d2275726c282360781b608582015260008651613468816096850160208b01613839565b7f292220643d224d32342034306131362031362030203020312031362d313668316096918401918201527f303030613136203136203020302031203136203136763931346131362031362060b68201527f30203020312d3136203136483131342e356132342032342030203020302d313760d68201527f2e3620372e376c2d35392036332e34613820382030203020312d31332e392d3560f682015269171a2b1a182d1110179f60b11b61011682015261363161361f6136196135fe6135f861353e61353861012088018e6131d5565b8c6131d5565b7f3c7465787420786d6c3a73706163653d227072657365727665222066696c6c3d81527f22233030394446352220666f6e742d66616d696c793d22436f7572696572222060208201527f666f6e742d73697a653d22323422206c65747465722d73706163696e673d223060408201527f656d22207374796c653d2277686974652d73706163653a707265223e3c74737060608201527530b7103c1e91189a1a11103c9e9118981a1a171c911f60511b608082015260960190565b896131d5565b6e1e17ba39b830b71f1e17ba32bc3a1f60891b8152600f0190565b866131d5565b651e17b9bb339f60d11b815260060190565b98975050505050505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613670908301846131a9565b9695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156136cf57815180518552868101516001600160a01b0316878601528501518585015260609093019290850190600101613697565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015613714578351835292840192918401916001016136f8565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561371457835160ff168352928401929184019160010161373c565b60208152600061120c60208301846131a9565b85815260a06020820152600061378760a08301876131a9565b828103604084015261379981876131a9565b91505061ffff80851660608401528084166080840152509695505050505050565b604051601f8201601f1916810167ffffffffffffffff811182821017156137e3576137e36138cb565b604052919050565b600082198211156137fe576137fe6138b5565b500190565b600081600019048311821515161561381d5761381d6138b5565b500290565b600082821015613834576138346138b5565b500390565b60005b8381101561385457818101518382015260200161383c565b838111156119565750506000910152565b600181811c9082168061387957607f821691505b60208210811415611c2457634e487b7160e01b600052602260045260246000fd5b60006000198214156138ae576138ae6138b5565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b031981168114610eb957600080fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef736861726520796f7572206d657373616765206174206e6f6e6f6e2e686f757365a26469706673582212206d095de219df15e46294140727498581aae7d369cc3a076e0839aca95b3c4fca64736f6c63430008040033

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

000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca6

-----Decoded View---------------
Arg [0] : tokenCollectionAddress (address): 0xD3607bc8c7927B348bac50dc224C28E3ce933ca6

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca6


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.