ETH Price: $3,882.17 (+1.46%)

Token

BEBO (BEBO)
 

Overview

Max Total Supply

2,788 BEBO

Holders

785

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
laotu.eth
Balance
1 BEBO
0xCc789E2342BE0C15661bE0b54CA82e9DF4336886
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:
BEBO

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, Unlicense license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-03-20
*/

// File: solidity-bits/contracts/BitScan.sol

/**
   _____       ___     ___ __           ____  _ __
  / ___/____  / (_)___/ (_) /___  __   / __ )(_) /______
  \__ \/ __ \/ / / __  / / __/ / / /  / __  / / __/ ___/
 ___/ / /_/ / / / /_/ / / /_/ /_/ /  / /_/ / / /_(__  )
/____/\____/_/_/\__,_/_/\__/\__, /  /_____/_/\__/____/
                           /____/

- npm: https://www.npmjs.com/package/solidity-bits
- github: https://github.com/estarriolvetch/solidity-bits

 */

pragma solidity ^0.8.0;


library BitScan {
    uint256 constant private DEBRUIJN_256 = 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff;
    bytes constant private LOOKUP_TABLE_256 = hex"0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8";

    /**
        @dev Isolate the least significant set bit.
     */
    function isolateLS1B256(uint256 bb) pure internal returns (uint256) {
        require(bb > 0);
        unchecked {
            return bb & (0 - bb);
        }
    }

    /**
        @dev Isolate the most significant set bit.
     */
    function isolateMS1B256(uint256 bb) pure internal returns (uint256) {
        require(bb > 0);
        unchecked {
            bb |= bb >> 128;
            bb |= bb >> 64;
            bb |= bb >> 32;
            bb |= bb >> 16;
            bb |= bb >> 8;
            bb |= bb >> 4;
            bb |= bb >> 2;
            bb |= bb >> 1;

            return (bb >> 1) + 1;
        }
    }

    /**
        @dev Find the index of the lest significant set bit. (trailing zero count)
     */
    function bitScanForward256(uint256 bb) pure internal returns (uint8) {
        unchecked {
            return uint8(LOOKUP_TABLE_256[(isolateLS1B256(bb) * DEBRUIJN_256) >> 248]);
        }
    }

    /**
        @dev Find the index of the most significant set bit.
     */
    function bitScanReverse256(uint256 bb) pure internal returns (uint8) {
        unchecked {
            return 255 - uint8(LOOKUP_TABLE_256[((isolateMS1B256(bb) * DEBRUIJN_256) >> 248)]);
        }
    }

    function log2(uint256 bb) pure internal returns (uint8) {
        unchecked {
            return uint8(LOOKUP_TABLE_256[(isolateMS1B256(bb) * DEBRUIJN_256) >> 248]);
        }
    }
}

// File: solidity-bits/contracts/BitMaps.sol

/**
   _____       ___     ___ __           ____  _ __
  / ___/____  / (_)___/ (_) /___  __   / __ )(_) /______
  \__ \/ __ \/ / / __  / / __/ / / /  / __  / / __/ ___/
 ___/ / /_/ / / / /_/ / / /_/ /_/ /  / /_/ / / /_(__  )
/____/\____/_/_/\__,_/_/\__/\__, /  /_____/_/\__/____/
                           /____/

- npm: https://www.npmjs.com/package/solidity-bits
- github: https://github.com/estarriolvetch/solidity-bits

 */
pragma solidity ^0.8.0;

/**
 * @dev This Library is a modified version of Openzeppelin's BitMaps library.
 * Functions of finding the index of the closest set bit from a given index are added.
 * The indexing of each bucket is modifed to count from the MSB to the LSB instead of from the LSB to the MSB.
 * The modification of indexing makes finding the closest previous set bit more efficient in gas usage.
*/

/**
 * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
 * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
 */

library BitMaps {
    using BitScan for uint256;
    uint256 private constant MASK_INDEX_ZERO = (1 << 255);
    uint256 private constant MASK_FULL = type(uint256).max;

    struct BitMap {
        mapping(uint256 => uint256) _data;
    }

    /**
     * @dev Returns whether the bit at `index` is set.
     */
    function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        return bitmap._data[bucket] & mask != 0;
    }

    /**
     * @dev Sets the bit at `index` to the boolean `value`.
     */
    function setTo(
        BitMap storage bitmap,
        uint256 index,
        bool value
    ) internal {
        if (value) {
            set(bitmap, index);
        } else {
            unset(bitmap, index);
        }
    }

    /**
     * @dev Sets the bit at `index`.
     */
    function set(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        bitmap._data[bucket] |= mask;
    }

    /**
     * @dev Unsets the bit at `index`.
     */
    function unset(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        bitmap._data[bucket] &= ~mask;
    }


    /**
     * @dev Consecutively sets `amount` of bits starting from the bit at `startIndex`.
     */
    function setBatch(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal {
        uint256 bucket = startIndex >> 8;

        uint256 bucketStartIndex = (startIndex & 0xff);

        unchecked {
            if(bucketStartIndex + amount < 256) {
                bitmap._data[bucket] |= MASK_FULL << (256 - amount) >> bucketStartIndex;
            } else {
                bitmap._data[bucket] |= MASK_FULL >> bucketStartIndex;
                amount -= (256 - bucketStartIndex);
                bucket++;

                while(amount > 256) {
                    bitmap._data[bucket] = MASK_FULL;
                    amount -= 256;
                    bucket++;
                }

                bitmap._data[bucket] |= MASK_FULL << (256 - amount);
            }
        }
    }


    /**
     * @dev Consecutively unsets `amount` of bits starting from the bit at `startIndex`.
     */
    function unsetBatch(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal {
        uint256 bucket = startIndex >> 8;

        uint256 bucketStartIndex = (startIndex & 0xff);

        unchecked {
            if(bucketStartIndex + amount < 256) {
                bitmap._data[bucket] &= ~(MASK_FULL << (256 - amount) >> bucketStartIndex);
            } else {
                bitmap._data[bucket] &= ~(MASK_FULL >> bucketStartIndex);
                amount -= (256 - bucketStartIndex);
                bucket++;

                while(amount > 256) {
                    bitmap._data[bucket] = 0;
                    amount -= 256;
                    bucket++;
                }

                bitmap._data[bucket] &= ~(MASK_FULL << (256 - amount));
            }
        }
    }


    /**
     * @dev Find the closest index of the set bit before `index`.
     */
    function scanForward(BitMap storage bitmap, uint256 index) internal view returns (uint256 setBitIndex) {
        uint256 bucket = index >> 8;

        // index within the bucket
        uint256 bucketIndex = (index & 0xff);

        // load a bitboard from the bitmap.
        uint256 bb = bitmap._data[bucket];

        // offset the bitboard to scan from `bucketIndex`.
        bb = bb >> (0xff ^ bucketIndex); // bb >> (255 - bucketIndex)

        if(bb > 0) {
            unchecked {
                setBitIndex = (bucket << 8) | (bucketIndex -  bb.bitScanForward256());
            }
        } else {
            while(true) {
                require(bucket > 0, "BitMaps: The set bit before the index doesn't exist.");
                unchecked {
                    bucket--;
                }
                // No offset. Always scan from the least significiant bit now.
                bb = bitmap._data[bucket];

                if(bb > 0) {
                    unchecked {
                        setBitIndex = (bucket << 8) | (255 -  bb.bitScanForward256());
                        break;
                    }
                }
            }
        }
    }

    function getBucket(BitMap storage bitmap, uint256 bucket) internal view returns (uint256) {
        return bitmap._data[bucket];
    }
}

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol

// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/token/ERC721/IERC721.sol


// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

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

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

// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol


// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

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

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

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

// File: @openzeppelin/contracts/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

// File: @openzeppelin/contracts/utils/math/Math.sol


// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

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

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

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

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

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

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

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

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

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// File: @openzeppelin/contracts/utils/Strings.sol


// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

// File: @openzeppelin/contracts/utils/introspection/ERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/utils/Address.sol


// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// File: @openzeppelin/contracts/utils/StorageSlot.sol


// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

// File: erc721psi/contracts/ERC721Psi.sol


/**
  ______ _____   _____ ______ ___  __ _  _  _
 |  ____|  __ \ / ____|____  |__ \/_ | || || |
 | |__  | |__) | |        / /   ) || | \| |/ |
 |  __| |  _  /| |       / /   / / | |\_   _/
 | |____| | \ \| |____  / /   / /_ | |  | |
 |______|_|  \_\\_____|/_/   |____||_|  |_|

 - github: https://github.com/estarriolvetch/ERC721Psi
 - npm: https://www.npmjs.com/package/erc721psi

 */

pragma solidity ^0.8.0;









contract ERC721Psi is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;
    using BitMaps for BitMaps.BitMap;

    BitMaps.BitMap private _batchHead;

    string private _name;
    string private _symbol;

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

    mapping(uint256 => address) private _tokenApprovals;
    mapping(address => mapping(address => bool)) private _operatorApprovals;

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

    /**
     * @dev Returns the starting token ID.
     * To change the starting token ID, please override this function.
     */
    function _startTokenId() internal pure returns (uint256) {
        // It will become modifiable in the future versions
        return 0;
    }

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

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


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

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

        uint count;
        for( uint i = _startTokenId(); i < _nextTokenId(); ++i ){
            if(_exists(i)){
                if( owner == ownerOf(i)){
                    ++count;
                }
            }
        }
        return count;
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId)
        public
        view
        virtual
        override
        returns (address)
    {
        (address owner, ) = _ownerAndBatchHeadOf(tokenId);
        return owner;
    }

    function _ownerAndBatchHeadOf(uint256 tokenId) internal view returns (address owner, uint256 tokenIdBatchHead){
        require(_exists(tokenId), "ERC721Psi: owner query for nonexistent token");
        tokenIdBatchHead = _getBatchHead(tokenId);
        owner = _owners[tokenIdBatchHead];
    }

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

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

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

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

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


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

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

        _approve(to, tokenId);
    }

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

        return _tokenApprovals[tokenId];
    }

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

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

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

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

        _transfer(from, to, tokenId);
    }

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

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

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

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return tokenId < _nextTokenId() && _startTokenId() <= tokenId;
    }

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

    /**
     * @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.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 quantity) internal virtual {
        _safeMint(to, quantity, "");
    }


    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual {
        uint256 nextTokenId = _nextTokenId();
        _mint(to, quantity);
        require(
            _checkOnERC721Received(address(0), to, nextTokenId, quantity, _data),
            "ERC721Psi: transfer to non ERC721Receiver implementer"
        );
    }


    function _mint(
        address to,
        uint256 quantity
    ) internal virtual {
        uint256 nextTokenId = _nextTokenId();

        require(quantity > 0, "ERC721Psi: quantity must be greater 0");
        require(to != address(0), "ERC721Psi: mint to the zero address");

        _beforeTokenTransfers(address(0), to, nextTokenId, quantity);
        _currentIndex += quantity;
        _owners[nextTokenId] = to;
        _batchHead.set(nextTokenId);
        _afterTokenTransfers(address(0), to, nextTokenId, quantity);

        // Emit events
        for(uint256 tokenId=nextTokenId; tokenId < nextTokenId + quantity; tokenId++){
            emit Transfer(address(0), to, tokenId);
        }
    }


    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        (address owner, uint256 tokenIdBatchHead) = _ownerAndBatchHeadOf(tokenId);

        require(
            owner == from,
            "ERC721Psi: transfer of token that is not own"
        );
        require(to != address(0), "ERC721Psi: transfer to the zero address");

        _beforeTokenTransfers(from, to, tokenId, 1);

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

        uint256 subsequentTokenId = tokenId + 1;

        if(!_batchHead.get(subsequentTokenId) &&
            subsequentTokenId < _nextTokenId()
        ) {
            _owners[subsequentTokenId] = from;
            _batchHead.set(subsequentTokenId);
        }

        _owners[tokenId] = to;
        if(tokenId != tokenIdBatchHead) {
            _batchHead.set(tokenId);
        }

        emit Transfer(from, to, tokenId);

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

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

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

    function _getBatchHead(uint256 tokenId) internal view returns (uint256 tokenIdBatchHead) {
        tokenIdBatchHead = _batchHead.scanForward(tokenId);
    }


    function totalSupply() public virtual view returns (uint256) {
        return _totalMinted();
    }

    /**
     * @dev Returns an array of token IDs owned by `owner`.
     *
     * This function scans the ownership mapping and is O(`totalSupply`) in complexity.
     * It is meant to be called off-chain.
     *
     * This function is compatiable with ERC721AQueryable.
     */
    function tokensOfOwner(address owner) external view virtual returns (uint256[] memory) {
        unchecked {
            uint256 tokenIdsIdx;
            uint256 tokenIdsLength = balanceOf(owner);
            uint256[] memory tokenIds = new uint256[](tokenIdsLength);
            for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) {
                if (_exists(i)) {
                    if (ownerOf(i) == owner) {
                        tokenIds[tokenIdsIdx++] = i;
                    }
                }
            }
            return tokenIds;
        }
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
     *
     * 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`.
     */
    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.
     *
     * 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` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}
}

// File: erc721psi/contracts/extension/ERC721PsiBurnable.sol


/**
  ______ _____   _____ ______ ___  __ _  _  _
 |  ____|  __ \ / ____|____  |__ \/_ | || || |
 | |__  | |__) | |        / /   ) || | \| |/ |
 |  __| |  _  /| |       / /   / / | |\_   _/
 | |____| | \ \| |____  / /   / /_ | |  | |
 |______|_|  \_\\_____|/_/   |____||_|  |_|


 */
pragma solidity ^0.8.0;


abstract contract ERC721PsiBurnable is ERC721Psi {
    using BitMaps for BitMaps.BitMap;
    BitMaps.BitMap private _burnedToken;

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

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

        _afterTokenTransfers(from, address(0), tokenId, 1);
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view override virtual returns (bool){
        if(_burnedToken.get(tokenId)) {
            return false;
        }
        return super._exists(tokenId);
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalMinted() - _burned();
    }

    /**
     * @dev Returns number of token burned.
     */
    function _burned() internal view returns (uint256 burned){
        uint256 startBucket = _startTokenId() >> 8;
        uint256 lastBucket = (_nextTokenId() >> 8) + 1;

        for(uint256 i=startBucket; i < lastBucket; i++) {
            uint256 bucket = _burnedToken.getBucket(i);
            burned += _popcount(bucket);
        }
    }

    /**
     * @dev Returns number of set bits.
     */
    function _popcount(uint256 x) private pure returns (uint256 count) {
        unchecked{
            for (count=0; x!=0; count++)
                x &= x - 1;
        }
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

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

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

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

// File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol


// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

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

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

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

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

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

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

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

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

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

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

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

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

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

// File: contracts/BEBO.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;



error MerkleProofVerificationFailed();
error CallerIsContract();
error MintIsOff();
error RoleCodeIsIllegal();
error AddressIsMinted();
error ReachMaxSupply();
error NeedSendMoreETH();
error TokenNotExistent();
error NotOwnerOrApproval();
error MintMoreThanAllowed();

contract BEBO is ERC721PsiBurnable, Ownable {
    using Strings for uint256;

    struct MintConfig {
        uint8 preMintMaxCount;
        uint8 publicMintMaxCount;
        uint32 preMintStartTime;
        uint32 publicMintStartTime;
        uint256 preMintPriceWei;
        uint256 publicMintPriceWei;
        string baseTokenURI;
        string blindTokenURI;
        bytes32 merkleRoot;
    }

    mapping(address => uint256) private _preMintedNum;
    mapping(address => uint256) private _publicMintedNum;
    bool public boxingOpen = false;
    uint256 public immutable collectionSize;
    MintConfig public config;

    constructor(uint256 collectionSize_) ERC721Psi("BEBO", "BEBO") {
        collectionSize = collectionSize_;
    }

    modifier callerIsUser() {
        if (tx.origin != msg.sender) {
            revert CallerIsContract();
        }
        _;
    }

    modifier lessThenMaxSupply(uint256 quantity) {
        if (totalSupply() + quantity > collectionSize) {
            revert ReachMaxSupply();
        }
        _;
    }

    function airdrop(address receiver,uint256 quantity)external onlyOwner lessThenMaxSupply(quantity){
        _safeMint(receiver, quantity);
    }

    function reserve(uint256 quantity)external onlyOwner lessThenMaxSupply(quantity){
        _safeMint(msg.sender, quantity);
    }

    function purchase(uint256 quantity, bytes32[] calldata merkleProof, uint8 roleCode) external payable returns(bool){
        // pre—mint
        if (roleCode == 1) {
            if (isOnlyPreMint(config.preMintStartTime, config.publicMintStartTime)) {
                bytes32 leaf = keccak256(abi.encodePacked(_msgSender()));
                if (!MerkleProof.verify(merkleProof, config.merkleRoot, leaf)) {
                    revert MerkleProofVerificationFailed();
                }
                _mintHelper(
                    msg.value,
                    config.preMintPriceWei,
                    config.preMintStartTime,
                    quantity
                );
                return true;
            }
        }
        // public—mint
        _mintHelper(
            msg.value,
            config.publicMintPriceWei,
            config.publicMintStartTime,
            quantity
        );
        return true;
    }

    function _mintHelper(
        uint256 ethValue,
        uint256 price,
        uint256 mintStartTime,
        uint256 quantity
    ) private callerIsUser lessThenMaxSupply(quantity) {
        if (!isSaleOn(mintStartTime, price)) {
            revert MintIsOff();
        }
        if (ethValue < price) {
            revert NeedSendMoreETH();
        }
        if (price == config.preMintPriceWei) {
            if (preMintedNum(msg.sender) + quantity > config.preMintMaxCount) {
                revert MintMoreThanAllowed();
            }
            _safeMint(msg.sender, quantity);
            _preMintedNum[msg.sender] += quantity;
        }

        if (price == config.publicMintPriceWei) {
            if (
                publicMintedNum(msg.sender) + quantity >
                config.publicMintMaxCount
            ) {
                revert MintMoreThanAllowed();
            }
            _safeMint(msg.sender, quantity);
            _publicMintedNum[msg.sender] += quantity;
        }
    }

    function burn(uint256 tokenId) external virtual {
        if (!_isApprovedOrOwner(_msgSender(), tokenId)) {
            revert NotOwnerOrApproval();
        }
        _burn(tokenId);
    }

    function withdrawMoney() external onlyOwner {
        (bool success, ) = msg.sender.call{value: address(this).balance}("");
        require(success, "Transfer failed");
    }

    function setConfig(
        uint8 preMintMaxCount,
        uint8 publicMintMaxCount,
        uint32 preMintStartTime,
        uint32 publicMintStartTime,
        uint256 preMintPriceWei,
        uint256 publicMintPriceWei
    ) external onlyOwner {
        config.preMintMaxCount = preMintMaxCount;
        config.publicMintMaxCount = publicMintMaxCount;
        config.preMintStartTime = preMintStartTime;
        config.publicMintStartTime = publicMintStartTime;
        config.preMintPriceWei = preMintPriceWei;
        config.publicMintPriceWei = publicMintPriceWei;
    }

    function setBaseURI(string calldata baseURI) external onlyOwner {
        config.baseTokenURI = baseURI;
    }

    function setMerkleRoot(bytes32 merkleRoot) external onlyOwner {
        config.merkleRoot = merkleRoot;
    }

    function setBlindTokenURI(string calldata blindTokenURI)
        external
        onlyOwner
    {
        config.blindTokenURI = blindTokenURI;
    }

    function setBoxingStatus(bool status) external onlyOwner {
        boxingOpen = status;
    }

    function isSaleOn(uint256 mintStartTime, uint256 price)
        public
        view
        returns (bool)
    {
        return
            mintStartTime != 0 &&
            price != 0 &&
            block.timestamp >= mintStartTime;
    }

    function isOnlyPreMint(uint32 preMintStartTime, uint32 publicMintStartTime)
        public
        view
        returns (bool)
    {
        return
            preMintStartTime != 0 &&
            block.timestamp < publicMintStartTime &&
            block.timestamp >= preMintStartTime;
    }

    function preMintedNum(address minter) public view returns (uint256) {
        return _preMintedNum[minter];
    }

    function publicMintedNum(address minter) public view returns (uint256) {
        return _publicMintedNum[minter];
    }

    function _baseURI()
        internal
        view
        virtual
        override(ERC721Psi)
        returns (string memory)
    {
        return config.baseTokenURI;
    }

    function tokenURI(uint256 tokenId)
        public
        view
        virtual
        override(ERC721Psi)
        returns (string memory)
    {
        if (!_exists(tokenId)) {
            revert TokenNotExistent();
        }
        if (boxingOpen) {
            return
                bytes(_baseURI()).length > 0
                    ? string(
                        abi.encodePacked(
                            _baseURI(),
                            tokenId.toString(),
                            ".json"
                        )
                    )
                    : "";
        } else {
            return config.blindTokenURI;
        }
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"collectionSize_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallerIsContract","type":"error"},{"inputs":[],"name":"MerkleProofVerificationFailed","type":"error"},{"inputs":[],"name":"MintIsOff","type":"error"},{"inputs":[],"name":"MintMoreThanAllowed","type":"error"},{"inputs":[],"name":"NeedSendMoreETH","type":"error"},{"inputs":[],"name":"NotOwnerOrApproval","type":"error"},{"inputs":[],"name":"ReachMaxSupply","type":"error"},{"inputs":[],"name":"TokenNotExistent","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","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":[],"name":"boxingOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectionSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"uint8","name":"preMintMaxCount","type":"uint8"},{"internalType":"uint8","name":"publicMintMaxCount","type":"uint8"},{"internalType":"uint32","name":"preMintStartTime","type":"uint32"},{"internalType":"uint32","name":"publicMintStartTime","type":"uint32"},{"internalType":"uint256","name":"preMintPriceWei","type":"uint256"},{"internalType":"uint256","name":"publicMintPriceWei","type":"uint256"},{"internalType":"string","name":"baseTokenURI","type":"string"},{"internalType":"string","name":"blindTokenURI","type":"string"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"stateMutability":"view","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":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"preMintStartTime","type":"uint32"},{"internalType":"uint32","name":"publicMintStartTime","type":"uint32"}],"name":"isOnlyPreMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintStartTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"isSaleOn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"preMintedNum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"publicMintedNum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint8","name":"roleCode","type":"uint8"}],"name":"purchase","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"reserve","outputs":[],"stateMutability":"nonpayable","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":"string","name":"baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"blindTokenURI","type":"string"}],"name":"setBlindTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"setBoxingStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"preMintMaxCount","type":"uint8"},{"internalType":"uint8","name":"publicMintMaxCount","type":"uint8"},{"internalType":"uint32","name":"preMintStartTime","type":"uint32"},{"internalType":"uint32","name":"publicMintStartTime","type":"uint32"},{"internalType":"uint256","name":"preMintPriceWei","type":"uint256"},{"internalType":"uint256","name":"publicMintPriceWei","type":"uint256"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","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":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"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":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawMoney","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a0604052600b805460ff191690553480156200001b57600080fd5b5060405162002d1238038062002d128339810160408190526200003e91620001a7565b6040805180820182526004808252634245424f60e01b6020808401828152855180870190965292855284015281519192916200007d9160019162000101565b5080516200009390600290602084019062000101565b5050600060045550620000a633620000af565b608052620001fe565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8280546200010f90620001c1565b90600052602060002090601f0160209004810192826200013357600085556200017e565b82601f106200014e57805160ff19168380011785556200017e565b828001600101855582156200017e579182015b828111156200017e57825182559160200191906001019062000161565b506200018c92915062000190565b5090565b5b808211156200018c576000815560010162000191565b600060208284031215620001ba57600080fd5b5051919050565b600181811c90821680620001d657607f821691505b60208210811415620001f857634e487b7160e01b600052602260045260246000fd5b50919050565b608051612ae36200022f600039600081816103a901528181610d6a01528181610e9c015261196d0152612ae36000f3fe6080604052600436106102045760003560e01c8063715018a611610118578063a22cb465116100a0578063c45633f41161006f578063c45633f41461062b578063c87b56dd1461063e578063dc2295d41461065e578063e985e9c51461067e578063f2fde38b146106c757600080fd5b8063a22cb465146105a0578063ac446002146105c0578063b88d4fde146105d5578063c297dc29146105f557600080fd5b80638462151c116100e75780638462151c146104ea5780638a7c1c9c146105175780638ba4cc3c1461054d5780638da5cb5b1461056d57806395d89b411461058b57600080fd5b8063715018a61461046b57806379502c55146104805780637cb64759146104aa578063819b25ba146104ca57600080fd5b806323b872dd1161019b5780634d50fd4d1161016a5780634d50fd4d146103cb57806355f804b3146103eb5780636352211e1461040b5780636b12304e1461042b57806370a082311461044b57600080fd5b806323b872dd1461033757806342842e0e1461035757806342966c681461037757806345c0f5331461039757600080fd5b8063095ea7b3116101d7578063095ea7b3146102ba5780630bd8d3b0146102da57806318160ddd146102f45780631dd856bd1461031757600080fd5b806301ffc9a71461020957806306fdde031461023e578063081812fc1461026057806308fc818814610298575b600080fd5b34801561021557600080fd5b5061022961022436600461249a565b6106e7565b60405190151581526020015b60405180910390f35b34801561024a57600080fd5b50610253610739565b6040516102359190612774565b34801561026c57600080fd5b5061028061027b366004612481565b6107cb565b6040516001600160a01b039091168152602001610235565b3480156102a457600080fd5b506102b86102b3366004612622565b61085b565b005b3480156102c657600080fd5b506102b86102d536600461243c565b6108c7565b3480156102e657600080fd5b50600b546102299060ff1681565b34801561030057600080fd5b506103096109df565b604051908152602001610235565b34801561032357600080fd5b506102296103323660046125f8565b610a00565b34801561034357600080fd5b506102b86103523660046122fa565b610a35565b34801561036357600080fd5b506102b86103723660046122fa565b610a67565b34801561038357600080fd5b506102b8610392366004612481565b610a82565b3480156103a357600080fd5b506103097f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d757600080fd5b506102b86103e6366004612466565b610ab4565b3480156103f757600080fd5b506102b86104063660046124d4565b610acf565b34801561041757600080fd5b50610280610426366004612481565b610ae3565b34801561043757600080fd5b506102296104463660046125d6565b610af7565b34801561045757600080fd5b506103096104663660046122ac565b610b16565b34801561047757600080fd5b506102b8610be5565b34801561048c57600080fd5b50610495610bf9565b60405161023599989796959493929190612830565b3480156104b657600080fd5b506102b86104c5366004612481565b610d52565b3480156104d657600080fd5b506102b86104e5366004612481565b610d5f565b3480156104f657600080fd5b5061050a6105053660046122ac565b610dc9565b6040516102359190612730565b34801561052357600080fd5b506103096105323660046122ac565b6001600160a01b031660009081526009602052604090205490565b34801561055957600080fd5b506102b861056836600461243c565b610e91565b34801561057957600080fd5b506008546001600160a01b0316610280565b34801561059757600080fd5b50610253610ef7565b3480156105ac57600080fd5b506102b86105bb366004612412565b610f06565b3480156105cc57600080fd5b506102b8610fcb565b3480156105e157600080fd5b506102b86105f0366004612336565b61105d565b34801561060157600080fd5b506103096106103660046122ac565b6001600160a01b03166000908152600a602052604090205490565b610229610639366004612546565b611095565b34801561064a57600080fd5b50610253610659366004612481565b6111b4565b34801561066a57600080fd5b506102b86106793660046124d4565b6112da565b34801561068a57600080fd5b506102296106993660046122c7565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205460ff1690565b3480156106d357600080fd5b506102b86106e23660046122ac565b6112ee565b60006001600160e01b031982166380ac58cd60e01b148061071857506001600160e01b03198216635b5e139f60e01b145b8061073357506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060018054610748906128ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610774906128ff565b80156107c15780601f10610796576101008083540402835291602001916107c1565b820191906000526020600020905b8154815290600101906020018083116107a457829003601f168201915b5050505050905090565b60006107d682611364565b61083f5760405162461bcd60e51b815260206004820152602f60248201527f4552433732315073693a20617070726f76656420717565727920666f72206e6f60448201526e3732bc34b9ba32b73a103a37b5b2b760891b60648201526084015b60405180910390fd5b506000908152600560205260409020546001600160a01b031690565b610863611399565b600c805460ff97881661ffff199091161761010096909716959095029590951769ffffffffffffffff000019166201000063ffffffff9485160269ffffffff000000000000191617600160301b929093169190910291909117909155600d55600e55565b60006108d282610ae3565b9050806001600160a01b0316836001600160a01b031614156109425760405162461bcd60e51b8152602060048201526024808201527f4552433732315073693a20617070726f76616c20746f2063757272656e74206f6044820152633bb732b960e11b6064820152608401610836565b336001600160a01b038216148061095e575061095e8133610699565b6109d05760405162461bcd60e51b815260206004820152603b60248201527f4552433732315073693a20617070726f76652063616c6c6572206973206e6f7460448201527f206f776e6572206e6f7220617070726f76656420666f7220616c6c00000000006064820152608401610836565b6109da83836113f3565b505050565b60006109e9611461565b6109f16114c3565b6109fb91906128bc565b905090565b600063ffffffff831615801590610a1c57508163ffffffff1642105b8015610a2e57508263ffffffff164210155b9392505050565b610a40335b826114d3565b610a5c5760405162461bcd60e51b8152600401610836906127dc565b6109da8383836115bc565b6109da8383836040518060200160405280600081525061105d565b610a8b33610a3a565b610aa857604051637783b71760e11b815260040160405180910390fd5b610ab1816117a8565b50565b610abc611399565b600b805460ff1916911515919091179055565b610ad7611399565b6109da600f83836121c7565b600080610aef836117fc565b509392505050565b60008215801590610b0757508115155b8015610a2e5750505042101590565b60006001600160a01b038216610b845760405162461bcd60e51b815260206004820152602d60248201527f4552433732315073693a2062616c616e636520717565727920666f722074686560448201526c207a65726f206164647265737360981b6064820152608401610836565b6000805b600454811015610bde57610b9b81611364565b15610bce57610ba981610ae3565b6001600160a01b0316846001600160a01b03161415610bce57610bcb8261293a565b91505b610bd78161293a565b9050610b88565b5092915050565b610bed611399565b610bf76000611893565b565b600c8054600d54600e54600f805460ff8086169661010087049091169563ffffffff620100008204811696600160301b909204169490939092610c3b906128ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610c67906128ff565b8015610cb45780601f10610c8957610100808354040283529160200191610cb4565b820191906000526020600020905b815481529060010190602001808311610c9757829003601f168201915b505050505090806004018054610cc9906128ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610cf5906128ff565b8015610d425780601f10610d1757610100808354040283529160200191610d42565b820191906000526020600020905b815481529060010190602001808311610d2557829003601f168201915b5050505050908060050154905089565b610d5a611399565b601155565b610d67611399565b807f000000000000000000000000000000000000000000000000000000000000000081610d926109df565b610d9c91906128a4565b1115610dbb57604051631a23bd9760e21b815260040160405180910390fd5b610dc533836118e5565b5050565b6060600080610dd784610b16565b905060008167ffffffffffffffff811115610df457610df4612981565b604051908082528060200260200182016040528015610e1d578160200160208202803683370190505b50905060005b828414610e8857610e3381611364565b15610e8057856001600160a01b0316610e4b82610ae3565b6001600160a01b03161415610e805780828580600101965081518110610e7357610e7361296b565b6020026020010181815250505b600101610e23565b50949350505050565b610e99611399565b807f000000000000000000000000000000000000000000000000000000000000000081610ec46109df565b610ece91906128a4565b1115610eed57604051631a23bd9760e21b815260040160405180910390fd5b6109da83836118e5565b606060028054610748906128ff565b6001600160a01b038216331415610f5f5760405162461bcd60e51b815260206004820152601c60248201527f4552433732315073693a20617070726f766520746f2063616c6c6572000000006044820152606401610836565b3360008181526006602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610fd3611399565b604051600090339047908381818185875af1925050503d8060008114611015576040519150601f19603f3d011682016040523d82523d6000602084013e61101a565b606091505b5050905080610ab15760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606401610836565b61106733836114d3565b6110835760405162461bcd60e51b8152600401610836906127dc565b61108f848484846118ff565b50505050565b60008160ff166001141561118957600c546110c59063ffffffff620100008204811691600160301b900416610a00565b15611189576040516bffffffffffffffffffffffff193360601b166020820152600090603401604051602081830303815290604052805190602001209050611144858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506011549150849050611934565b611161576040516360cf18d960e11b815260040160405180910390fd5b600d54600c5461117f91349162010000900463ffffffff168961194a565b60019150506111ac565b600e54600c546111a8913491600160301b900463ffffffff168861194a565b5060015b949350505050565b60606111bf82611364565b6111dc576040516339f2d95f60e21b815260040160405180910390fd5b600b5460ff16156112435760006111f1611b16565b511161120c5760405180602001604052806000815250610733565b611214611b16565b61121d83611b28565b60405160200161122e9291906126b4565b60405160208183030381529060405292915050565b60108054611250906128ff565b80601f016020809104026020016040519081016040528092919081815260200182805461127c906128ff565b80156112c95780601f1061129e576101008083540402835291602001916112c9565b820191906000526020600020905b8154815290600101906020018083116112ac57829003601f168201915b50505050509050919050565b919050565b6112e2611399565b6109da601083836121c7565b6112f6611399565b6001600160a01b03811661135b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610836565b610ab181611893565b600881901c600090815260076020526040812054600160ff1b60ff84161c161561139057506000919050565b61073382611bbd565b6008546001600160a01b03163314610bf75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610836565b600081815260056020526040902080546001600160a01b0319166001600160a01b038416908117909155819061142882610ae3565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600454600090819081906114799060081c60016128a4565b9050815b818110156114bd5760008181526007602052604090205461149d81611bd9565b6114a790866128a4565b94505080806114b59061293a565b91505061147d565b50505090565b6000806004546109fb91906128bc565b60006114de82611364565b6115425760405162461bcd60e51b815260206004820152602f60248201527f4552433732315073693a206f70657261746f7220717565727920666f72206e6f60448201526e3732bc34b9ba32b73a103a37b5b2b760891b6064820152608401610836565b600061154d83610ae3565b9050806001600160a01b0316846001600160a01b031614806115885750836001600160a01b031661157d846107cb565b6001600160a01b0316145b806111ac57506001600160a01b0380821660009081526006602090815260408083209388168352929052205460ff166111ac565b6000806115c8836117fc565b91509150846001600160a01b0316826001600160a01b0316146116425760405162461bcd60e51b815260206004820152602c60248201527f4552433732315073693a207472616e73666572206f6620746f6b656e2074686160448201526b3a1034b9903737ba1037bbb760a11b6064820152608401610836565b6001600160a01b0384166116a85760405162461bcd60e51b815260206004820152602760248201527f4552433732315073693a207472616e7366657220746f20746865207a65726f206044820152666164647265737360c81b6064820152608401610836565b6116b36000846113f3565b60006116c08460016128a4565b600881901c600090815260208190526040902054909150600160ff1b60ff83161c161580156116f0575060045481105b1561172657600081815260036020526040812080546001600160a01b0319166001600160a01b0389161790556117269082611bf3565b600084815260036020526040902080546001600160a01b0319166001600160a01b03871617905581841461175f5761175f600085611bf3565b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b60006117b382610ae3565b90506117c0600783611bf3565b60405182906000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b60008061180883611364565b6118695760405162461bcd60e51b815260206004820152602c60248201527f4552433732315073693a206f776e657220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610836565b61187283611c1f565b6000818152600360205260409020546001600160a01b031694909350915050565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b610dc5828260405180602001604052806000815250611c2b565b61190a8484846115bc565b611918848484600185611c4c565b61108f5760405162461bcd60e51b815260040161083690612787565b6000826119418584611d8f565b14949350505050565b32331461196a57604051637df1f81760e01b815260040160405180910390fd5b807f0000000000000000000000000000000000000000000000000000000000000000816119956109df565b61199f91906128a4565b11156119be57604051631a23bd9760e21b815260040160405180910390fd5b6119c88385610af7565b6119e55760405163ced265fb60e01b815260040160405180910390fd5b83851015611a0657604051635399efaf60e11b815260040160405180910390fd5b600d54841415611a8e57600c5460ff1682611a36336001600160a01b031660009081526009602052604090205490565b611a4091906128a4565b1115611a5f5760405163b234809160e01b815260040160405180910390fd5b611a6933836118e5565b3360009081526009602052604081208054849290611a889084906128a4565b90915550505b600e54841415611b0f57600c54336000908152600a602052604090205461010090910460ff16908390611ac191906128a4565b1115611ae05760405163b234809160e01b815260040160405180910390fd5b611aea33836118e5565b336000908152600a602052604081208054849290611b099084906128a4565b90915550505b5050505050565b6060600c6003018054610748906128ff565b60606000611b3583611dd4565b600101905060008167ffffffffffffffff811115611b5557611b55612981565b6040519080825280601f01601f191660200182016040528015611b7f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611bb857610aef565b611b89565b6000611bc860045490565b821080156107335750600192915050565b60005b81156112d557600019820190911690600101611bdc565b600881901c600090815260209290925260409091208054600160ff1b60ff9093169290921c9091179055565b60006107338183611eac565b6000611c3660045490565b9050611c428484611fa4565b6119186000858386865b60006001600160a01b0385163b15611d8257506001835b611c6d84866128a4565b811015611d7c57604051630a85bd0160e11b81526001600160a01b0387169063150b7a0290611ca69033908b90869089906004016126f3565b602060405180830381600087803b158015611cc057600080fd5b505af1925050508015611cf0575060408051601f3d908101601f19168201909252611ced918101906124b7565b60015b611d4a573d808015611d1e576040519150601f19603f3d011682016040523d82523d6000602084013e611d23565b606091505b508051611d425760405162461bcd60e51b815260040161083690612787565b805181602001fd5b828015611d6757506001600160e01b03198116630a85bd0160e11b145b92505080611d748161293a565b915050611c63565b50611d86565b5060015b95945050505050565b600081815b8451811015610aef57611dc082868381518110611db357611db361296b565b6020026020010151612116565b915080611dcc8161293a565b915050611d94565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611e135772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611e3f576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611e5d57662386f26fc10000830492506010015b6305f5e1008310611e75576305f5e100830492506008015b6127108310611e8957612710830492506004015b60648310611e9b576064830492506002015b600a83106107335760010192915050565b600881901c60008181526020849052604081205490919060ff808516919082181c8015611eee57611edc81612145565b60ff168203600884901b179350611f9b565b60008311611f5b5760405162461bcd60e51b815260206004820152603460248201527f4269744d6170733a205468652073657420626974206265666f7265207468652060448201527334b73232bc103237b2b9b713ba1032bc34b9ba1760611b6064820152608401610836565b506000199091016000818152602086905260409020549091908015611f9657611f8381612145565b60ff0360ff16600884901b179350611f9b565b611eee565b50505092915050565b6000611faf60045490565b90506000821161200f5760405162461bcd60e51b815260206004820152602560248201527f4552433732315073693a207175616e74697479206d7573742062652067726561604482015264074657220360dc1b6064820152608401610836565b6001600160a01b0383166120715760405162461bcd60e51b815260206004820152602360248201527f4552433732315073693a206d696e7420746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610836565b816004600082825461208391906128a4565b9091555050600081815260036020526040812080546001600160a01b0319166001600160a01b0386161790556120b99082611bf3565b805b6120c583836128a4565b81101561108f5760405181906001600160a01b038616906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a48061210e8161293a565b9150506120bb565b6000818310612132576000828152602084905260409020610a2e565b6000838152602083905260409020610a2e565b600060405180610120016040528061010081526020016129ae610100913960f87e818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff61218e856121af565b02901c815181106121a1576121a161296b565b016020015160f81c92915050565b60008082116121bd57600080fd5b5060008190031690565b8280546121d3906128ff565b90600052602060002090601f0160209004810192826121f5576000855561223b565b82601f1061220e5782800160ff1982351617855561223b565b8280016001018555821561223b579182015b8281111561223b578235825591602001919060010190612220565b5061224792915061224b565b5090565b5b80821115612247576000815560010161224c565b80356001600160a01b03811681146112d557600080fd5b803580151581146112d557600080fd5b803563ffffffff811681146112d557600080fd5b803560ff811681146112d557600080fd5b6000602082840312156122be57600080fd5b610a2e82612260565b600080604083850312156122da57600080fd5b6122e383612260565b91506122f160208401612260565b90509250929050565b60008060006060848603121561230f57600080fd5b61231884612260565b925061232660208501612260565b9150604084013590509250925092565b6000806000806080858703121561234c57600080fd5b61235585612260565b935061236360208601612260565b925060408501359150606085013567ffffffffffffffff8082111561238757600080fd5b818701915087601f83011261239b57600080fd5b8135818111156123ad576123ad612981565b604051601f8201601f19908116603f011681019083821181831017156123d5576123d5612981565b816040528281528a60208487010111156123ee57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6000806040838503121561242557600080fd5b61242e83612260565b91506122f160208401612277565b6000806040838503121561244f57600080fd5b61245883612260565b946020939093013593505050565b60006020828403121561247857600080fd5b610a2e82612277565b60006020828403121561249357600080fd5b5035919050565b6000602082840312156124ac57600080fd5b8135610a2e81612997565b6000602082840312156124c957600080fd5b8151610a2e81612997565b600080602083850312156124e757600080fd5b823567ffffffffffffffff808211156124ff57600080fd5b818501915085601f83011261251357600080fd5b81358181111561252257600080fd5b86602082850101111561253457600080fd5b60209290920196919550909350505050565b6000806000806060858703121561255c57600080fd5b84359350602085013567ffffffffffffffff8082111561257b57600080fd5b818701915087601f83011261258f57600080fd5b81358181111561259e57600080fd5b8860208260051b85010111156125b357600080fd5b6020830195508094505050506125cb6040860161229b565b905092959194509250565b600080604083850312156125e957600080fd5b50508035926020909101359150565b6000806040838503121561260b57600080fd5b61261483612287565b91506122f160208401612287565b60008060008060008060c0878903121561263b57600080fd5b6126448761229b565b95506126526020880161229b565b945061266060408801612287565b935061266e60608801612287565b92506080870135915060a087013590509295509295509295565b600081518084526126a08160208601602086016128d3565b601f01601f19169290920160200192915050565b600083516126c68184602088016128d3565b8351908301906126da8183602088016128d3565b64173539b7b760d91b9101908152600501949350505050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061272690830184612688565b9695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156127685783518352928401929184019160010161274c565b50909695505050505050565b602081526000610a2e6020830184612688565b60208082526035908201527f4552433732315073693a207472616e7366657220746f206e6f6e20455243373260408201527418a932b1b2b4bb32b91034b6b83632b6b2b73a32b960591b606082015260800190565b60208082526034908201527f4552433732315073693a207472616e736665722063616c6c6572206973206e6f6040820152731d081bdddb995c881b9bdc88185c1c1c9bdd995960621b606082015260800190565b600061012060ff8c16835260ff8b16602084015263ffffffff808b166040850152808a166060850152508760808401528660a08401528060c084015261287881840187612688565b905082810360e084015261288c8186612688565b915050826101008301529a9950505050505050505050565b600082198211156128b7576128b7612955565b500190565b6000828210156128ce576128ce612955565b500390565b60005b838110156128ee5781810151838201526020016128d6565b8381111561108f5750506000910152565b600181811c9082168061291357607f821691505b6020821081141561293457634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561294e5761294e612955565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b031981168114610ab157600080fdfe0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8a2646970667358221220edaa081e48ebd6dc219c36d3be676a704dbb139d53617eee43332fb4a30a77a664736f6c634300080700330000000000000000000000000000000000000000000000000000000000001700

Deployed Bytecode

0x6080604052600436106102045760003560e01c8063715018a611610118578063a22cb465116100a0578063c45633f41161006f578063c45633f41461062b578063c87b56dd1461063e578063dc2295d41461065e578063e985e9c51461067e578063f2fde38b146106c757600080fd5b8063a22cb465146105a0578063ac446002146105c0578063b88d4fde146105d5578063c297dc29146105f557600080fd5b80638462151c116100e75780638462151c146104ea5780638a7c1c9c146105175780638ba4cc3c1461054d5780638da5cb5b1461056d57806395d89b411461058b57600080fd5b8063715018a61461046b57806379502c55146104805780637cb64759146104aa578063819b25ba146104ca57600080fd5b806323b872dd1161019b5780634d50fd4d1161016a5780634d50fd4d146103cb57806355f804b3146103eb5780636352211e1461040b5780636b12304e1461042b57806370a082311461044b57600080fd5b806323b872dd1461033757806342842e0e1461035757806342966c681461037757806345c0f5331461039757600080fd5b8063095ea7b3116101d7578063095ea7b3146102ba5780630bd8d3b0146102da57806318160ddd146102f45780631dd856bd1461031757600080fd5b806301ffc9a71461020957806306fdde031461023e578063081812fc1461026057806308fc818814610298575b600080fd5b34801561021557600080fd5b5061022961022436600461249a565b6106e7565b60405190151581526020015b60405180910390f35b34801561024a57600080fd5b50610253610739565b6040516102359190612774565b34801561026c57600080fd5b5061028061027b366004612481565b6107cb565b6040516001600160a01b039091168152602001610235565b3480156102a457600080fd5b506102b86102b3366004612622565b61085b565b005b3480156102c657600080fd5b506102b86102d536600461243c565b6108c7565b3480156102e657600080fd5b50600b546102299060ff1681565b34801561030057600080fd5b506103096109df565b604051908152602001610235565b34801561032357600080fd5b506102296103323660046125f8565b610a00565b34801561034357600080fd5b506102b86103523660046122fa565b610a35565b34801561036357600080fd5b506102b86103723660046122fa565b610a67565b34801561038357600080fd5b506102b8610392366004612481565b610a82565b3480156103a357600080fd5b506103097f000000000000000000000000000000000000000000000000000000000000170081565b3480156103d757600080fd5b506102b86103e6366004612466565b610ab4565b3480156103f757600080fd5b506102b86104063660046124d4565b610acf565b34801561041757600080fd5b50610280610426366004612481565b610ae3565b34801561043757600080fd5b506102296104463660046125d6565b610af7565b34801561045757600080fd5b506103096104663660046122ac565b610b16565b34801561047757600080fd5b506102b8610be5565b34801561048c57600080fd5b50610495610bf9565b60405161023599989796959493929190612830565b3480156104b657600080fd5b506102b86104c5366004612481565b610d52565b3480156104d657600080fd5b506102b86104e5366004612481565b610d5f565b3480156104f657600080fd5b5061050a6105053660046122ac565b610dc9565b6040516102359190612730565b34801561052357600080fd5b506103096105323660046122ac565b6001600160a01b031660009081526009602052604090205490565b34801561055957600080fd5b506102b861056836600461243c565b610e91565b34801561057957600080fd5b506008546001600160a01b0316610280565b34801561059757600080fd5b50610253610ef7565b3480156105ac57600080fd5b506102b86105bb366004612412565b610f06565b3480156105cc57600080fd5b506102b8610fcb565b3480156105e157600080fd5b506102b86105f0366004612336565b61105d565b34801561060157600080fd5b506103096106103660046122ac565b6001600160a01b03166000908152600a602052604090205490565b610229610639366004612546565b611095565b34801561064a57600080fd5b50610253610659366004612481565b6111b4565b34801561066a57600080fd5b506102b86106793660046124d4565b6112da565b34801561068a57600080fd5b506102296106993660046122c7565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205460ff1690565b3480156106d357600080fd5b506102b86106e23660046122ac565b6112ee565b60006001600160e01b031982166380ac58cd60e01b148061071857506001600160e01b03198216635b5e139f60e01b145b8061073357506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060018054610748906128ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610774906128ff565b80156107c15780601f10610796576101008083540402835291602001916107c1565b820191906000526020600020905b8154815290600101906020018083116107a457829003601f168201915b5050505050905090565b60006107d682611364565b61083f5760405162461bcd60e51b815260206004820152602f60248201527f4552433732315073693a20617070726f76656420717565727920666f72206e6f60448201526e3732bc34b9ba32b73a103a37b5b2b760891b60648201526084015b60405180910390fd5b506000908152600560205260409020546001600160a01b031690565b610863611399565b600c805460ff97881661ffff199091161761010096909716959095029590951769ffffffffffffffff000019166201000063ffffffff9485160269ffffffff000000000000191617600160301b929093169190910291909117909155600d55600e55565b60006108d282610ae3565b9050806001600160a01b0316836001600160a01b031614156109425760405162461bcd60e51b8152602060048201526024808201527f4552433732315073693a20617070726f76616c20746f2063757272656e74206f6044820152633bb732b960e11b6064820152608401610836565b336001600160a01b038216148061095e575061095e8133610699565b6109d05760405162461bcd60e51b815260206004820152603b60248201527f4552433732315073693a20617070726f76652063616c6c6572206973206e6f7460448201527f206f776e6572206e6f7220617070726f76656420666f7220616c6c00000000006064820152608401610836565b6109da83836113f3565b505050565b60006109e9611461565b6109f16114c3565b6109fb91906128bc565b905090565b600063ffffffff831615801590610a1c57508163ffffffff1642105b8015610a2e57508263ffffffff164210155b9392505050565b610a40335b826114d3565b610a5c5760405162461bcd60e51b8152600401610836906127dc565b6109da8383836115bc565b6109da8383836040518060200160405280600081525061105d565b610a8b33610a3a565b610aa857604051637783b71760e11b815260040160405180910390fd5b610ab1816117a8565b50565b610abc611399565b600b805460ff1916911515919091179055565b610ad7611399565b6109da600f83836121c7565b600080610aef836117fc565b509392505050565b60008215801590610b0757508115155b8015610a2e5750505042101590565b60006001600160a01b038216610b845760405162461bcd60e51b815260206004820152602d60248201527f4552433732315073693a2062616c616e636520717565727920666f722074686560448201526c207a65726f206164647265737360981b6064820152608401610836565b6000805b600454811015610bde57610b9b81611364565b15610bce57610ba981610ae3565b6001600160a01b0316846001600160a01b03161415610bce57610bcb8261293a565b91505b610bd78161293a565b9050610b88565b5092915050565b610bed611399565b610bf76000611893565b565b600c8054600d54600e54600f805460ff8086169661010087049091169563ffffffff620100008204811696600160301b909204169490939092610c3b906128ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610c67906128ff565b8015610cb45780601f10610c8957610100808354040283529160200191610cb4565b820191906000526020600020905b815481529060010190602001808311610c9757829003601f168201915b505050505090806004018054610cc9906128ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610cf5906128ff565b8015610d425780601f10610d1757610100808354040283529160200191610d42565b820191906000526020600020905b815481529060010190602001808311610d2557829003601f168201915b5050505050908060050154905089565b610d5a611399565b601155565b610d67611399565b807f000000000000000000000000000000000000000000000000000000000000170081610d926109df565b610d9c91906128a4565b1115610dbb57604051631a23bd9760e21b815260040160405180910390fd5b610dc533836118e5565b5050565b6060600080610dd784610b16565b905060008167ffffffffffffffff811115610df457610df4612981565b604051908082528060200260200182016040528015610e1d578160200160208202803683370190505b50905060005b828414610e8857610e3381611364565b15610e8057856001600160a01b0316610e4b82610ae3565b6001600160a01b03161415610e805780828580600101965081518110610e7357610e7361296b565b6020026020010181815250505b600101610e23565b50949350505050565b610e99611399565b807f000000000000000000000000000000000000000000000000000000000000170081610ec46109df565b610ece91906128a4565b1115610eed57604051631a23bd9760e21b815260040160405180910390fd5b6109da83836118e5565b606060028054610748906128ff565b6001600160a01b038216331415610f5f5760405162461bcd60e51b815260206004820152601c60248201527f4552433732315073693a20617070726f766520746f2063616c6c6572000000006044820152606401610836565b3360008181526006602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610fd3611399565b604051600090339047908381818185875af1925050503d8060008114611015576040519150601f19603f3d011682016040523d82523d6000602084013e61101a565b606091505b5050905080610ab15760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606401610836565b61106733836114d3565b6110835760405162461bcd60e51b8152600401610836906127dc565b61108f848484846118ff565b50505050565b60008160ff166001141561118957600c546110c59063ffffffff620100008204811691600160301b900416610a00565b15611189576040516bffffffffffffffffffffffff193360601b166020820152600090603401604051602081830303815290604052805190602001209050611144858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506011549150849050611934565b611161576040516360cf18d960e11b815260040160405180910390fd5b600d54600c5461117f91349162010000900463ffffffff168961194a565b60019150506111ac565b600e54600c546111a8913491600160301b900463ffffffff168861194a565b5060015b949350505050565b60606111bf82611364565b6111dc576040516339f2d95f60e21b815260040160405180910390fd5b600b5460ff16156112435760006111f1611b16565b511161120c5760405180602001604052806000815250610733565b611214611b16565b61121d83611b28565b60405160200161122e9291906126b4565b60405160208183030381529060405292915050565b60108054611250906128ff565b80601f016020809104026020016040519081016040528092919081815260200182805461127c906128ff565b80156112c95780601f1061129e576101008083540402835291602001916112c9565b820191906000526020600020905b8154815290600101906020018083116112ac57829003601f168201915b50505050509050919050565b919050565b6112e2611399565b6109da601083836121c7565b6112f6611399565b6001600160a01b03811661135b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610836565b610ab181611893565b600881901c600090815260076020526040812054600160ff1b60ff84161c161561139057506000919050565b61073382611bbd565b6008546001600160a01b03163314610bf75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610836565b600081815260056020526040902080546001600160a01b0319166001600160a01b038416908117909155819061142882610ae3565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600454600090819081906114799060081c60016128a4565b9050815b818110156114bd5760008181526007602052604090205461149d81611bd9565b6114a790866128a4565b94505080806114b59061293a565b91505061147d565b50505090565b6000806004546109fb91906128bc565b60006114de82611364565b6115425760405162461bcd60e51b815260206004820152602f60248201527f4552433732315073693a206f70657261746f7220717565727920666f72206e6f60448201526e3732bc34b9ba32b73a103a37b5b2b760891b6064820152608401610836565b600061154d83610ae3565b9050806001600160a01b0316846001600160a01b031614806115885750836001600160a01b031661157d846107cb565b6001600160a01b0316145b806111ac57506001600160a01b0380821660009081526006602090815260408083209388168352929052205460ff166111ac565b6000806115c8836117fc565b91509150846001600160a01b0316826001600160a01b0316146116425760405162461bcd60e51b815260206004820152602c60248201527f4552433732315073693a207472616e73666572206f6620746f6b656e2074686160448201526b3a1034b9903737ba1037bbb760a11b6064820152608401610836565b6001600160a01b0384166116a85760405162461bcd60e51b815260206004820152602760248201527f4552433732315073693a207472616e7366657220746f20746865207a65726f206044820152666164647265737360c81b6064820152608401610836565b6116b36000846113f3565b60006116c08460016128a4565b600881901c600090815260208190526040902054909150600160ff1b60ff83161c161580156116f0575060045481105b1561172657600081815260036020526040812080546001600160a01b0319166001600160a01b0389161790556117269082611bf3565b600084815260036020526040902080546001600160a01b0319166001600160a01b03871617905581841461175f5761175f600085611bf3565b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b60006117b382610ae3565b90506117c0600783611bf3565b60405182906000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b60008061180883611364565b6118695760405162461bcd60e51b815260206004820152602c60248201527f4552433732315073693a206f776e657220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610836565b61187283611c1f565b6000818152600360205260409020546001600160a01b031694909350915050565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b610dc5828260405180602001604052806000815250611c2b565b61190a8484846115bc565b611918848484600185611c4c565b61108f5760405162461bcd60e51b815260040161083690612787565b6000826119418584611d8f565b14949350505050565b32331461196a57604051637df1f81760e01b815260040160405180910390fd5b807f0000000000000000000000000000000000000000000000000000000000001700816119956109df565b61199f91906128a4565b11156119be57604051631a23bd9760e21b815260040160405180910390fd5b6119c88385610af7565b6119e55760405163ced265fb60e01b815260040160405180910390fd5b83851015611a0657604051635399efaf60e11b815260040160405180910390fd5b600d54841415611a8e57600c5460ff1682611a36336001600160a01b031660009081526009602052604090205490565b611a4091906128a4565b1115611a5f5760405163b234809160e01b815260040160405180910390fd5b611a6933836118e5565b3360009081526009602052604081208054849290611a889084906128a4565b90915550505b600e54841415611b0f57600c54336000908152600a602052604090205461010090910460ff16908390611ac191906128a4565b1115611ae05760405163b234809160e01b815260040160405180910390fd5b611aea33836118e5565b336000908152600a602052604081208054849290611b099084906128a4565b90915550505b5050505050565b6060600c6003018054610748906128ff565b60606000611b3583611dd4565b600101905060008167ffffffffffffffff811115611b5557611b55612981565b6040519080825280601f01601f191660200182016040528015611b7f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611bb857610aef565b611b89565b6000611bc860045490565b821080156107335750600192915050565b60005b81156112d557600019820190911690600101611bdc565b600881901c600090815260209290925260409091208054600160ff1b60ff9093169290921c9091179055565b60006107338183611eac565b6000611c3660045490565b9050611c428484611fa4565b6119186000858386865b60006001600160a01b0385163b15611d8257506001835b611c6d84866128a4565b811015611d7c57604051630a85bd0160e11b81526001600160a01b0387169063150b7a0290611ca69033908b90869089906004016126f3565b602060405180830381600087803b158015611cc057600080fd5b505af1925050508015611cf0575060408051601f3d908101601f19168201909252611ced918101906124b7565b60015b611d4a573d808015611d1e576040519150601f19603f3d011682016040523d82523d6000602084013e611d23565b606091505b508051611d425760405162461bcd60e51b815260040161083690612787565b805181602001fd5b828015611d6757506001600160e01b03198116630a85bd0160e11b145b92505080611d748161293a565b915050611c63565b50611d86565b5060015b95945050505050565b600081815b8451811015610aef57611dc082868381518110611db357611db361296b565b6020026020010151612116565b915080611dcc8161293a565b915050611d94565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611e135772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611e3f576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611e5d57662386f26fc10000830492506010015b6305f5e1008310611e75576305f5e100830492506008015b6127108310611e8957612710830492506004015b60648310611e9b576064830492506002015b600a83106107335760010192915050565b600881901c60008181526020849052604081205490919060ff808516919082181c8015611eee57611edc81612145565b60ff168203600884901b179350611f9b565b60008311611f5b5760405162461bcd60e51b815260206004820152603460248201527f4269744d6170733a205468652073657420626974206265666f7265207468652060448201527334b73232bc103237b2b9b713ba1032bc34b9ba1760611b6064820152608401610836565b506000199091016000818152602086905260409020549091908015611f9657611f8381612145565b60ff0360ff16600884901b179350611f9b565b611eee565b50505092915050565b6000611faf60045490565b90506000821161200f5760405162461bcd60e51b815260206004820152602560248201527f4552433732315073693a207175616e74697479206d7573742062652067726561604482015264074657220360dc1b6064820152608401610836565b6001600160a01b0383166120715760405162461bcd60e51b815260206004820152602360248201527f4552433732315073693a206d696e7420746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610836565b816004600082825461208391906128a4565b9091555050600081815260036020526040812080546001600160a01b0319166001600160a01b0386161790556120b99082611bf3565b805b6120c583836128a4565b81101561108f5760405181906001600160a01b038616906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a48061210e8161293a565b9150506120bb565b6000818310612132576000828152602084905260409020610a2e565b6000838152602083905260409020610a2e565b600060405180610120016040528061010081526020016129ae610100913960f87e818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff61218e856121af565b02901c815181106121a1576121a161296b565b016020015160f81c92915050565b60008082116121bd57600080fd5b5060008190031690565b8280546121d3906128ff565b90600052602060002090601f0160209004810192826121f5576000855561223b565b82601f1061220e5782800160ff1982351617855561223b565b8280016001018555821561223b579182015b8281111561223b578235825591602001919060010190612220565b5061224792915061224b565b5090565b5b80821115612247576000815560010161224c565b80356001600160a01b03811681146112d557600080fd5b803580151581146112d557600080fd5b803563ffffffff811681146112d557600080fd5b803560ff811681146112d557600080fd5b6000602082840312156122be57600080fd5b610a2e82612260565b600080604083850312156122da57600080fd5b6122e383612260565b91506122f160208401612260565b90509250929050565b60008060006060848603121561230f57600080fd5b61231884612260565b925061232660208501612260565b9150604084013590509250925092565b6000806000806080858703121561234c57600080fd5b61235585612260565b935061236360208601612260565b925060408501359150606085013567ffffffffffffffff8082111561238757600080fd5b818701915087601f83011261239b57600080fd5b8135818111156123ad576123ad612981565b604051601f8201601f19908116603f011681019083821181831017156123d5576123d5612981565b816040528281528a60208487010111156123ee57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6000806040838503121561242557600080fd5b61242e83612260565b91506122f160208401612277565b6000806040838503121561244f57600080fd5b61245883612260565b946020939093013593505050565b60006020828403121561247857600080fd5b610a2e82612277565b60006020828403121561249357600080fd5b5035919050565b6000602082840312156124ac57600080fd5b8135610a2e81612997565b6000602082840312156124c957600080fd5b8151610a2e81612997565b600080602083850312156124e757600080fd5b823567ffffffffffffffff808211156124ff57600080fd5b818501915085601f83011261251357600080fd5b81358181111561252257600080fd5b86602082850101111561253457600080fd5b60209290920196919550909350505050565b6000806000806060858703121561255c57600080fd5b84359350602085013567ffffffffffffffff8082111561257b57600080fd5b818701915087601f83011261258f57600080fd5b81358181111561259e57600080fd5b8860208260051b85010111156125b357600080fd5b6020830195508094505050506125cb6040860161229b565b905092959194509250565b600080604083850312156125e957600080fd5b50508035926020909101359150565b6000806040838503121561260b57600080fd5b61261483612287565b91506122f160208401612287565b60008060008060008060c0878903121561263b57600080fd5b6126448761229b565b95506126526020880161229b565b945061266060408801612287565b935061266e60608801612287565b92506080870135915060a087013590509295509295509295565b600081518084526126a08160208601602086016128d3565b601f01601f19169290920160200192915050565b600083516126c68184602088016128d3565b8351908301906126da8183602088016128d3565b64173539b7b760d91b9101908152600501949350505050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061272690830184612688565b9695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156127685783518352928401929184019160010161274c565b50909695505050505050565b602081526000610a2e6020830184612688565b60208082526035908201527f4552433732315073693a207472616e7366657220746f206e6f6e20455243373260408201527418a932b1b2b4bb32b91034b6b83632b6b2b73a32b960591b606082015260800190565b60208082526034908201527f4552433732315073693a207472616e736665722063616c6c6572206973206e6f6040820152731d081bdddb995c881b9bdc88185c1c1c9bdd995960621b606082015260800190565b600061012060ff8c16835260ff8b16602084015263ffffffff808b166040850152808a166060850152508760808401528660a08401528060c084015261287881840187612688565b905082810360e084015261288c8186612688565b915050826101008301529a9950505050505050505050565b600082198211156128b7576128b7612955565b500190565b6000828210156128ce576128ce612955565b500390565b60005b838110156128ee5781810151838201526020016128d6565b8381111561108f5750506000910152565b600181811c9082168061291357607f821691505b6020821081141561293457634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561294e5761294e612955565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b031981168114610ab157600080fdfe0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8a2646970667358221220edaa081e48ebd6dc219c36d3be676a704dbb139d53617eee43332fb4a30a77a664736f6c63430008070033

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

0000000000000000000000000000000000000000000000000000000000001700

-----Decoded View---------------
Arg [0] : collectionSize_ (uint256): 5888

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


Deployed Bytecode Sourcemap

77936:6582:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47965:355;;;;;;;;;;-1:-1:-1;47965:355:0;;;;;:::i;:::-;;:::i;:::-;;;9455:14:1;;9448:22;9430:41;;9418:2;9403:18;47965:355:0;;;;;;;;49525:100;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;51080:311::-;;;;;;;;;;-1:-1:-1;51080:311:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;8116:32:1;;;8098:51;;8086:2;8071:18;51080:311:0;7952:203:1;81723:590:0;;;;;;;;;;-1:-1:-1;81723:590:0;;;;;:::i;:::-;;:::i;:::-;;50604:410;;;;;;;;;;-1:-1:-1;50604:410:0;;;;;:::i;:::-;;:::i;78469:30::-;;;;;;;;;;-1:-1:-1;78469:30:0;;;;;;;;64505:122;;;;;;;;;;;;;:::i;:::-;;;16708:25:1;;;16696:2;16681:18;64505:122:0;16562:177:1;83081:301:0;;;;;;;;;;-1:-1:-1;83081:301:0;;;;;:::i;:::-;;:::i;52145:379::-;;;;;;;;;;-1:-1:-1;52145:379:0;;;;;:::i;:::-;;:::i;52595:185::-;;;;;;;;;;-1:-1:-1;52595:185:0;;;;;:::i;:::-;;:::i;81337:193::-;;;;;;;;;;-1:-1:-1;81337:193:0;;;;;:::i;:::-;;:::i;78506:39::-;;;;;;;;;;;;;;;82722:95;;;;;;;;;;-1:-1:-1;82722:95:0;;;;;:::i;:::-;;:::i;82321:112::-;;;;;;;;;;-1:-1:-1;82321:112:0;;;;;:::i;:::-;;:::i;48930:222::-;;;;;;;;;;-1:-1:-1;48930:222:0;;;;;:::i;:::-;;:::i;82825:248::-;;;;;;;;;;-1:-1:-1;82825:248:0;;;;;:::i;:::-;;:::i;48384:484::-;;;;;;;;;;-1:-1:-1;48384:484:0;;;;;:::i;:::-;;:::i;67176:103::-;;;;;;;;;;;;;:::i;78552:24::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;82441:111::-;;;;;;;;;;-1:-1:-1;82441:111:0;;;;;:::i;:::-;;:::i;79183:130::-;;;;;;;;;;-1:-1:-1;79183:130:0;;;;;:::i;:::-;;:::i;61026:598::-;;;;;;;;;;-1:-1:-1;61026:598:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;83390:115::-;;;;;;;;;;-1:-1:-1;83390:115:0;;;;;:::i;:::-;-1:-1:-1;;;;;83476:21:0;83449:7;83476:21;;;:13;:21;;;;;;;83390:115;79030:145;;;;;;;;;;-1:-1:-1;79030:145:0;;;;;:::i;:::-;;:::i;66528:87::-;;;;;;;;;;-1:-1:-1;66601:6:0;;-1:-1:-1;;;;;66601:6:0;66528:87;;49694:104;;;;;;;;;;;;;:::i;51463:330::-;;;;;;;;;;-1:-1:-1;51463:330:0;;;;;:::i;:::-;;:::i;81538:177::-;;;;;;;;;;;;;:::i;52851:368::-;;;;;;;;;;-1:-1:-1;52851:368:0;;;;;:::i;:::-;;:::i;83513:121::-;;;;;;;;;;-1:-1:-1;83513:121:0;;;;;:::i;:::-;-1:-1:-1;;;;;83602:24:0;83575:7;83602:24;;;:16;:24;;;;;;;83513:121;79321:967;;;;;;:::i;:::-;;:::i;83831:684::-;;;;;;;;;;-1:-1:-1;83831:684:0;;;;;:::i;:::-;;:::i;82560:154::-;;;;;;;;;;-1:-1:-1;82560:154:0;;;;;:::i;:::-;;:::i;51864:214::-;;;;;;;;;;-1:-1:-1;51864:214:0;;;;;:::i;:::-;-1:-1:-1;;;;;52035:25:0;;;52006:4;52035:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;51864:214;67434:201;;;;;;;;;;-1:-1:-1;67434:201:0;;;;;:::i;:::-;;:::i;47965:355::-;48112:4;-1:-1:-1;;;;;;48154:40:0;;-1:-1:-1;;;48154:40:0;;:105;;-1:-1:-1;;;;;;;48211:48:0;;-1:-1:-1;;;48211:48:0;48154:105;:158;;;-1:-1:-1;;;;;;;;;;33616:40:0;;;48276:36;48134:178;47965:355;-1:-1:-1;;47965:355:0:o;49525:100::-;49579:13;49612:5;49605:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49525:100;:::o;51080:311::-;51201:7;51248:16;51256:7;51248;:16::i;:::-;51226:113;;;;-1:-1:-1;;;51226:113:0;;10659:2:1;51226:113:0;;;10641:21:1;10698:2;10678:18;;;10671:30;10737:34;10717:18;;;10710:62;-1:-1:-1;;;10788:18:1;;;10781:45;10843:19;;51226:113:0;;;;;;;;;-1:-1:-1;51359:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;51359:24:0;;51080:311::o;81723:590::-;66414:13;:11;:13::i;:::-;81988:6:::1;:40:::0;;::::1;::::0;;::::1;-1:-1:-1::0;;82039:46:0;;;;81988:40:::1;82039:46:::0;;;::::1;::::0;;;::::1;::::0;;;::::1;-1:-1:-1::0;;82149:48:0;82096:42;::::1;::::0;;::::1;;-1:-1:-1::0;;82149:48:0;;-1:-1:-1;;;82149:48:0;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;;82208:22;:40;82259:25;:46;81723:590::o;50604:410::-;50685:13;50701:16;50709:7;50701;:16::i;:::-;50685:32;;50742:5;-1:-1:-1;;;;;50736:11:0;:2;-1:-1:-1;;;;;50736:11:0;;;50728:60;;;;-1:-1:-1;;;50728:60:0;;13080:2:1;50728:60:0;;;13062:21:1;13119:2;13099:18;;;13092:30;13158:34;13138:18;;;13131:62;-1:-1:-1;;;13209:18:1;;;13202:34;13253:19;;50728:60:0;12878:400:1;50728:60:0;17313:10;-1:-1:-1;;;;;50823:21:0;;;;:62;;-1:-1:-1;50848:37:0;50865:5;17313:10;51864:214;:::i;50848:37::-;50801:171;;;;-1:-1:-1;;;50801:171:0;;15923:2:1;50801:171:0;;;15905:21:1;15962:2;15942:18;;;15935:30;16001:34;15981:18;;;15974:62;16072:29;16052:18;;;16045:57;16119:19;;50801:171:0;15721:423:1;50801:171:0;50985:21;50994:2;50998:7;50985:8;:21::i;:::-;50674:340;50604:410;;:::o;64505:122::-;64566:7;64610:9;:7;:9::i;:::-;64593:14;:12;:14::i;:::-;:26;;;;:::i;:::-;64586:33;;64505:122;:::o;83081:301::-;83205:4;83247:21;;;;;;;:75;;;83303:19;83285:37;;:15;:37;83247:75;:127;;;;;83358:16;83339:35;;:15;:35;;83247:127;83227:147;83081:301;-1:-1:-1;;;83081:301:0:o;52145:379::-;52354:41;17313:10;52373:12;52387:7;52354:18;:41::i;:::-;52332:143;;;;-1:-1:-1;;;52332:143:0;;;;;;;:::i;:::-;52488:28;52498:4;52504:2;52508:7;52488:9;:28::i;52595:185::-;52733:39;52750:4;52756:2;52760:7;52733:39;;;;;;;;;;;;:16;:39::i;81337:193::-;81401:41;17313:10;81420:12;17233:98;81401:41;81396:102;;81466:20;;-1:-1:-1;;;81466:20:0;;;;;;;;;;;81396:102;81508:14;81514:7;81508:5;:14::i;:::-;81337:193;:::o;82722:95::-;66414:13;:11;:13::i;:::-;82790:10:::1;:19:::0;;-1:-1:-1;;82790:19:0::1;::::0;::::1;;::::0;;;::::1;::::0;;82722:95::o;82321:112::-;66414:13;:11;:13::i;:::-;82396:29:::1;:19:::0;82418:7;;82396:29:::1;:::i;48930:222::-:0;49047:7;49073:13;49092:29;49113:7;49092:20;:29::i;:::-;-1:-1:-1;49072:49:0;48930:222;-1:-1:-1;;;48930:222:0:o;82825:248::-;82929:4;82971:18;;;;;:45;;-1:-1:-1;83006:10:0;;;82971:45;:94;;;;-1:-1:-1;;;83033:15:0;:32;;;82825:248::o;48384:484::-;48501:4;-1:-1:-1;;;;;48531:19:0;;48523:77;;;;-1:-1:-1;;;48523:77:0;;11075:2:1;48523:77:0;;;11057:21:1;11114:2;11094:18;;;11087:30;11153:34;11133:18;;;11126:62;-1:-1:-1;;;11204:18:1;;;11197:43;11257:19;;48523:77:0;10873:409:1;48523:77:0;48613:10;;48634:204;47651:13;;48665:1;:18;48634:204;;;48708:10;48716:1;48708:7;:10::i;:::-;48705:122;;;48751:10;48759:1;48751:7;:10::i;:::-;-1:-1:-1;;;;;48742:19:0;:5;-1:-1:-1;;;;;48742:19:0;;48738:74;;;48785:7;;;:::i;:::-;;;48738:74;48685:3;;;:::i;:::-;;;48634:204;;;-1:-1:-1;48855:5:0;48384:484;-1:-1:-1;;48384:484:0:o;67176:103::-;66414:13;:11;:13::i;:::-;67241:30:::1;67268:1;67241:18;:30::i;:::-;67176:103::o:0;78552:24::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;78552:24:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;82441:111::-;66414:13;:11;:13::i;:::-;82514:17;:30;82441:111::o;79183:130::-;66414:13;:11;:13::i;:::-;79254:8:::1;78937:14;78926:8;78910:13;:11;:13::i;:::-;:24;;;;:::i;:::-;:41;78906:97;;;78975:16;;-1:-1:-1::0;;;78975:16:0::1;;;;;;;;;;;78906:97;79274:31:::2;79284:10;79296:8;79274:9;:31::i;:::-;66438:1:::1;79183:130:::0;:::o;61026:598::-;61095:16;61149:19;61183:22;61208:16;61218:5;61208:9;:16::i;:::-;61183:41;;61239:25;61281:14;61267:29;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;61267:29:0;-1:-1:-1;61239:57:0;-1:-1:-1;61316:9:0;61311:265;61360:14;61345:11;:29;61311:265;;61404:10;61412:1;61404:7;:10::i;:::-;61400:161;;;61457:5;-1:-1:-1;;;;;61443:19:0;:10;61451:1;61443:7;:10::i;:::-;-1:-1:-1;;;;;61443:19:0;;61439:103;;;61517:1;61491:8;61500:13;;;;;;61491:23;;;;;;;;:::i;:::-;;;;;;:27;;;;;61439:103;61376:3;;61311:265;;;-1:-1:-1;61597:8:0;61026:598;-1:-1:-1;;;;61026:598:0:o;79030:145::-;66414:13;:11;:13::i;:::-;79118:8:::1;78937:14;78926:8;78910:13;:11;:13::i;:::-;:24;;;;:::i;:::-;:41;78906:97;;;78975:16;;-1:-1:-1::0;;;78975:16:0::1;;;;;;;;;;;78906:97;79138:29:::2;79148:8;79158;79138:9;:29::i;49694:104::-:0;49750:13;49783:7;49776:14;;;;;:::i;51463:330::-;-1:-1:-1;;;;;51598:24:0;;17313:10;51598:24;;51590:65;;;;-1:-1:-1;;;51590:65:0;;11489:2:1;51590:65:0;;;11471:21:1;11528:2;11508:18;;;11501:30;11567;11547:18;;;11540:58;11615:18;;51590:65:0;11287:352:1;51590:65:0;17313:10;51668:32;;;;:18;:32;;;;;;;;-1:-1:-1;;;;;51668:42:0;;;;;;;;;;;;:53;;-1:-1:-1;;51668:53:0;;;;;;;;;;51737:48;;9430:41:1;;;51668:42:0;;17313:10;51737:48;;9403:18:1;51737:48:0;;;;;;;51463:330;;:::o;81538:177::-;66414:13;:11;:13::i;:::-;81612:49:::1;::::0;81594:12:::1;::::0;81612:10:::1;::::0;81635:21:::1;::::0;81594:12;81612:49;81594:12;81612:49;81635:21;81612:10;:49:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81593:68;;;81680:7;81672:35;;;::::0;-1:-1:-1;;;81672:35:0;;10315:2:1;81672:35:0::1;::::0;::::1;10297:21:1::0;10354:2;10334:18;;;10327:30;-1:-1:-1;;;10373:18:1;;;10366:45;10428:18;;81672:35:0::1;10113:339:1::0;52851:368:0;53040:41;17313:10;53073:7;53040:18;:41::i;:::-;53018:143;;;;-1:-1:-1;;;53018:143:0;;;;;;;:::i;:::-;53172:39;53186:4;53192:2;53196:7;53205:5;53172:13;:39::i;:::-;52851:368;;;;:::o;79321:967::-;79430:4;79473:8;:13;;79485:1;79473:13;79469:603;;;79521:6;:23;79507:66;;79521:23;;;;;;;-1:-1:-1;;;79546:26:0;;;79507:13;:66::i;:::-;79503:558;;;79619:30;;-1:-1:-1;;17313:10:0;7015:2:1;7011:15;7007:53;79619:30:0;;;6995:66:1;79594:12:0;;7077::1;;79619:30:0;;;;;;;;;;;;79609:41;;;;;;79594:56;;79674;79693:11;;79674:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;79706:17:0;;;-1:-1:-1;79725:4:0;;-1:-1:-1;79674:18:0;:56::i;:::-;79669:144;;79762:31;;-1:-1:-1;;;79762:31:0;;;;;;;;;;;79669:144;79897:22;;:6;79942:23;79831:184;;79865:9;;79942:23;;;;;79988:8;79831:11;:184::i;:::-;80041:4;80034:11;;;;;79503:558;80158:25;;:6;80198:26;80108:150;;80134:9;;-1:-1:-1;;;80198:26:0;;;;80239:8;80108:11;:150::i;:::-;-1:-1:-1;80276:4:0;79321:967;;;;;;;:::o;83831:684::-;83960:13;83996:16;84004:7;83996;:16::i;:::-;83991:75;;84036:18;;-1:-1:-1;;;84036:18:0;;;;;;;;;;;83991:75;84080:10;;;;84076:432;;;84158:1;84137:10;:8;:10::i;:::-;84131:24;:28;:305;;;;;;;;;;;;;;;;;84263:10;:8;:10::i;:::-;84304:18;:7;:16;:18::i;:::-;84216:171;;;;;;;;;:::i;:::-;;;;;;;;;;;;;84107:329;83831:684;-1:-1:-1;;83831:684:0:o;84076:432::-;84476:20;84469:27;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83831:684;;;:::o;84076:432::-;83831:684;;;:::o;82560:154::-;66414:13;:11;:13::i;:::-;82670:36:::1;:20:::0;82693:13;;82670:36:::1;:::i;67434:201::-:0;66414:13;:11;:13::i;:::-;-1:-1:-1;;;;;67523:22:0;::::1;67515:73;;;::::0;-1:-1:-1;;;67515:73:0;;9908:2:1;67515:73:0::1;::::0;::::1;9890:21:1::0;9947:2;9927:18;;;9920:30;9986:34;9966:18;;;9959:62;-1:-1:-1;;;10037:18:1;;;10030:36;10083:19;;67515:73:0::1;9706:402:1::0;67515:73:0::1;67599:28;67618:8;67599:18;:28::i;64223:206::-:0;4375:1;4366:10;;;64297:4;4453:20;;;64316:12;4453:20;;;;;;-1:-1:-1;;;4430:4:0;4422:12;;4402:33;4453:27;:32;64313:69;;-1:-1:-1;64365:5:0;;64223:206;-1:-1:-1;64223:206:0:o;64313:69::-;64399:22;64413:7;64399:13;:22::i;66693:132::-;66601:6;;-1:-1:-1;;;;;66601:6:0;17313:10;66757:23;66749:68;;;;-1:-1:-1;;;66749:68:0;;13485:2:1;66749:68:0;;;13467:21:1;;;13504:18;;;13497:30;13563:34;13543:18;;;13536:62;13615:18;;66749:68:0;13283:356:1;58593:167:0;58668:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;58668:29:0;-1:-1:-1;;;;;58668:29:0;;;;;;;;:24;;58722:16;58668:24;58722:7;:16::i;:::-;-1:-1:-1;;;;;58713:39:0;;;;;;;;;;;58593:167;;:::o;64698:346::-;47651:13;;64740:14;;;;;;64840:25;;64807:1;64841:19;64864:1;64840:25;:::i;:::-;64819:46;-1:-1:-1;64892:11:0;64878:159;64909:10;64905:1;:14;64878:159;;;64941:14;8637:20;;;64958:12;8637:20;;;;;;65008:17;8637:20;65008:9;:17::i;:::-;64998:27;;;;:::i;:::-;;;64926:111;64921:3;;;;;:::i;:::-;;;;64878:159;;;;64755:289;;64698:346;:::o;47770:121::-;47825:7;;47852:13;;:31;;;;:::i;55031:448::-;55160:4;55204:16;55212:7;55204;:16::i;:::-;55182:113;;;;-1:-1:-1;;;55182:113:0;;15507:2:1;55182:113:0;;;15489:21:1;15546:2;15526:18;;;15519:30;15585:34;15565:18;;;15558:62;-1:-1:-1;;;15636:18:1;;;15629:45;15691:19;;55182:113:0;15305:411:1;55182:113:0;55306:13;55322:16;55330:7;55322;:16::i;:::-;55306:32;;55368:5;-1:-1:-1;;;;;55357:16:0;:7;-1:-1:-1;;;;;55357:16:0;;:64;;;;55414:7;-1:-1:-1;;;;;55390:31:0;:20;55402:7;55390:11;:20::i;:::-;-1:-1:-1;;;;;55390:31:0;;55357:64;:113;;;-1:-1:-1;;;;;;52035:25:0;;;52006:4;52035:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;55438:32;51864:214;57423:1052;57548:13;57563:24;57591:29;57612:7;57591:20;:29::i;:::-;57547:73;;;;57664:4;-1:-1:-1;;;;;57655:13:0;:5;-1:-1:-1;;;;;57655:13:0;;57633:107;;;;-1:-1:-1;;;57633:107:0;;15094:2:1;57633:107:0;;;15076:21:1;15133:2;15113:18;;;15106:30;15172:34;15152:18;;;15145:62;-1:-1:-1;;;15223:18:1;;;15216:42;15275:19;;57633:107:0;14892:408:1;57633:107:0;-1:-1:-1;;;;;57759:16:0;;57751:68;;;;-1:-1:-1;;;57751:68:0;;12672:2:1;57751:68:0;;;12654:21:1;12711:2;12691:18;;;12684:30;12750:34;12730:18;;;12723:62;-1:-1:-1;;;12801:18:1;;;12794:37;12848:19;;57751:68:0;12470:403:1;57751:68:0;57940:29;57957:1;57961:7;57940:8;:29::i;:::-;57982:25;58010:11;:7;58020:1;58010:11;:::i;:::-;4375:1;4366:10;;;58038;4453:20;;;;;;;;;;;4366:10;;-1:-1:-1;;;;4430:4:0;4422:12;;4402:33;4453:27;:32;;;58037:85;;-1:-1:-1;47651:13:0;;58088:17;:34;58037:85;58034:208;;;58149:26;;;;:7;:26;;;;;:33;;-1:-1:-1;;;;;;58149:33:0;-1:-1:-1;;;;;58149:33:0;;;;;58197;;58149:26;58197:14;:33::i;:::-;58254:16;;;;:7;:16;;;;;:21;;-1:-1:-1;;;;;;58254:21:0;-1:-1:-1;;;;;58254:21:0;;;;;58289:27;;;58286:82;;58333:23;:10;58348:7;58333:14;:23::i;:::-;58404:7;58400:2;-1:-1:-1;;;;;58385:27:0;58394:4;-1:-1:-1;;;;;58385:27:0;;;;;;;;;;;57536:939;;;57423:1052;;;:::o;63597:313::-;63657:12;63672:16;63680:7;63672;:16::i;:::-;63657:31;;63761:25;:12;63778:7;63761:16;:25::i;:::-;63804:35;;63831:7;;63827:1;;-1:-1:-1;;;;;63804:35:0;;;;;63827:1;;63804:35;66438:1:::1;79183:130:::0;:::o;49160:298::-;49230:13;49245:24;49289:16;49297:7;49289;:16::i;:::-;49281:73;;;;-1:-1:-1;;;49281:73:0;;16351:2:1;49281:73:0;;;16333:21:1;16390:2;16370:18;;;16363:30;16429:34;16409:18;;;16402:62;-1:-1:-1;;;16480:18:1;;;16473:42;16532:19;;49281:73:0;16149:408:1;49281:73:0;49384:22;49398:7;49384:13;:22::i;:::-;49425:25;;;;:7;:25;;;;;;-1:-1:-1;;;;;49425:25:0;;49365:41;;-1:-1:-1;49160:298:0;-1:-1:-1;;49160:298:0:o;67795:191::-;67888:6;;;-1:-1:-1;;;;;67905:17:0;;;-1:-1:-1;;;;;;67905:17:0;;;;;;;67938:40;;67888:6;;;67905:17;67888:6;;67938:40;;67869:16;;67938:40;67858:128;67795:191;:::o;55842:112::-;55919:27;55929:2;55933:8;55919:27;;;;;;;;;;;;:9;:27::i;54101:357::-;54258:28;54268:4;54274:2;54278:7;54258:9;:28::i;:::-;54319:50;54342:4;54348:2;54352:7;54361:1;54363:5;54319:22;:50::i;:::-;54297:153;;;;-1:-1:-1;;;54297:153:0;;;;;;;:::i;69215:190::-;69340:4;69393;69364:25;69377:5;69384:4;69364:12;:25::i;:::-;:33;;69215:190;-1:-1:-1;;;;69215:190:0:o;80296:1033::-;78746:9;78759:10;78746:23;78742:81;;78793:18;;-1:-1:-1;;;78793:18:0;;;;;;;;;;;78742:81;80473:8:::1;78937:14;78926:8;78910:13;:11;:13::i;:::-;:24;;;;:::i;:::-;:41;78906:97;;;78975:16;;-1:-1:-1::0;;;78975:16:0::1;;;;;;;;;;;78906:97;80499:30:::2;80508:13;80523:5;80499:8;:30::i;:::-;80494:82;;80553:11;;-1:-1:-1::0;;;80553:11:0::2;;;;;;;;;;;80494:82;80601:5;80590:8;:16;80586:73;;;80630:17;;-1:-1:-1::0;;;80630:17:0::2;;;;;;;;;;;80586:73;80682:22:::0;;80673:31;::::2;80669:290;;;80763:6;:22:::0;::::2;;80752:8:::0;80725:24:::2;80738:10;-1:-1:-1::0;;;;;83476:21:0;83449:7;83476:21;;;:13;:21;;;;;;;83390:115;80725:24:::2;:35;;;;:::i;:::-;:60;80721:129;;;80813:21;;-1:-1:-1::0;;;80813:21:0::2;;;;;;;;;;;80721:129;80864:31;80874:10;80886:8;80864:9;:31::i;:::-;80924:10;80910:25;::::0;;;:13:::2;:25;::::0;;;;:37;;80939:8;;80910:25;:37:::2;::::0;80939:8;;80910:37:::2;:::i;:::-;::::0;;;-1:-1:-1;;80669:290:0::2;80984:25:::0;;80975:34;::::2;80971:351;;;81106:6;:25:::0;81064:10:::2;83575:7:::0;83602:24;;;:16;:24;;;;;;81106:25:::2;::::0;;::::2;;;::::0;81078:8;;81048:38:::2;;;;:::i;:::-;:83;81026:184;;;81173:21;;-1:-1:-1::0;;;81173:21:0::2;;;;;;;;;;;81026:184;81224:31;81234:10;81246:8;81224:9;:31::i;:::-;81287:10;81270:28;::::0;;;:16:::2;:28;::::0;;;;:40;;81302:8;;81270:28;:40:::2;::::0;81302:8;;81270:40:::2;:::i;:::-;::::0;;;-1:-1:-1;;80971:351:0::2;78833:1:::1;80296:1033:::0;;;;:::o;83642:181::-;83758:13;83796:6;:19;;83789:26;;;;;:::i;30750:716::-;30806:13;30857:14;30874:17;30885:5;30874:10;:17::i;:::-;30894:1;30874:21;30857:38;;30910:20;30944:6;30933:18;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;30933:18:0;-1:-1:-1;30910:41:0;-1:-1:-1;31075:28:0;;;31091:2;31075:28;31132:288;-1:-1:-1;;31164:5:0;-1:-1:-1;;;31301:2:0;31290:14;;31285:30;31164:5;31272:44;31362:2;31353:11;;;-1:-1:-1;31387:10:0;31383:21;;31399:5;;31383:21;31132:288;;54713:151;54778:4;54812:14;47651:13;;;47569:103;54812:14;54802:7;:24;:54;;;;-1:-1:-1;54830:26:0;;54795:61;-1:-1:-1;;54713:151:0:o;65111:177::-;65163:13;65213:56;65227:4;;65213:56;;-1:-1:-1;;65264:5:0;;65259:10;;;;65268:1;65233:7;65213:56;;4879:204;4976:1;4967:10;;;4950:14;5047:20;;;;;;;;;;;;:28;;-1:-1:-1;;;5031:4:0;5023:12;;;5003:33;;;;5047:28;;;;;4879:204::o;60461:158::-;60524:24;60580:31;60524:24;60603:7;60580:22;:31::i;55964:387::-;56095:19;56117:14;47651:13;;;47569:103;56117:14;56095:36;;56142:19;56148:2;56152:8;56142:5;:19::i;:::-;56194:68;56225:1;56229:2;56233:11;56246:8;56256:5;59414:1039;59601:6;-1:-1:-1;;;;;59624:13:0;;35199:19;:23;59620:826;;-1:-1:-1;59660:4:0;59701:12;59679:689;59725:23;59740:8;59725:12;:23;:::i;:::-;59715:7;:33;59679:689;;;59783:72;;-1:-1:-1;;;59783:72:0;;-1:-1:-1;;;;;59783:36:0;;;;;:72;;17313:10;;59834:4;;59840:7;;59849:5;;59783:72;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;59783:72:0;;;;;;;;-1:-1:-1;;59783:72:0;;;;;;;;;;;;:::i;:::-;;;59779:574;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;60039:13:0;;60035:299;;60086:63;;-1:-1:-1;;;60086:63:0;;;;;;;:::i;60035:299::-;60276:6;60270:13;60261:6;60257:2;60253:15;60246:38;59779:574;59907:1;:56;;;;-1:-1:-1;;;;;;;59912:51:0;;-1:-1:-1;;;59912:51:0;59907:56;59903:60;;59856:127;59750:9;;;;:::i;:::-;;;;59679:689;;;;60382:8;;59620:826;-1:-1:-1;60430:4:0;59620:826;59414:1039;;;;;;;:::o;70082:296::-;70165:7;70208:4;70165:7;70223:118;70247:5;:12;70243:1;:16;70223:118;;;70296:33;70306:12;70320:5;70326:1;70320:8;;;;;;;;:::i;:::-;;;;;;;70296:9;:33::i;:::-;70281:48;-1:-1:-1;70261:3:0;;;;:::i;:::-;;;;70223:118;;27618:922;27671:7;;-1:-1:-1;;;27749:15:0;;27745:102;;-1:-1:-1;;;27785:15:0;;;-1:-1:-1;27829:2:0;27819:12;27745:102;27874:6;27865:5;:15;27861:102;;27910:6;27901:15;;;-1:-1:-1;27945:2:0;27935:12;27861:102;27990:6;27981:5;:15;27977:102;;28026:6;28017:15;;;-1:-1:-1;28061:2:0;28051:12;27977:102;28106:5;28097;:14;28093:99;;28141:5;28132:14;;;-1:-1:-1;28175:1:0;28165:11;28093:99;28219:5;28210;:14;28206:99;;28254:5;28245:14;;;-1:-1:-1;28288:1:0;28278:11;28206:99;28332:5;28323;:14;28319:99;;28367:5;28358:14;;;-1:-1:-1;28401:1:0;28391:11;28319:99;28445:5;28436;:14;28432:66;;28481:1;28471:11;28526:6;27618:922;-1:-1:-1;;27618:922:0:o;7316:1205::-;7456:1;7447:10;;;7398:19;7613:20;;;;;;;;;;;7398:19;;7447:10;7537:4;7529:12;;;;7718:18;;;7711:26;7782:6;;7779:735;;7880:22;:2;:20;:22::i;:::-;7865:37;;:11;:37;7859:1;7849:6;:11;;7848:55;7834:69;;7779:735;;;7999:1;7990:6;:10;7982:75;;;;-1:-1:-1;;;7982:75:0;;13846:2:1;7982:75:0;;;13828:21:1;13885:2;13865:18;;;13858:30;13924:34;13904:18;;;13897:62;-1:-1:-1;;;13975:18:1;;;13968:50;14035:19;;7982:75:0;13644:416:1;7982:75:0;-1:-1:-1;;;8109:8:0;;;8240:12;:20;;;;;;;;;;;8109:8;;-1:-1:-1;8284:6:0;;8281:207;;8390:22;:2;:20;:22::i;:::-;8383:3;:29;8366:47;;8377:1;8367:6;:11;;8366:47;8352:61;;8440:5;;8281:207;7951:552;;;7419:1102;;;7316:1205;;;;:::o;56361:723::-;56459:19;56481:14;47651:13;;;47569:103;56481:14;56459:36;;56527:1;56516:8;:12;56508:62;;;;-1:-1:-1;;;56508:62:0;;14688:2:1;56508:62:0;;;14670:21:1;14727:2;14707:18;;;14700:30;14766:34;14746:18;;;14739:62;-1:-1:-1;;;14817:18:1;;;14810:35;14862:19;;56508:62:0;14486:401:1;56508:62:0;-1:-1:-1;;;;;56589:16:0;;56581:64;;;;-1:-1:-1;;;56581:64:0;;12268:2:1;56581:64:0;;;12250:21:1;12307:2;12287:18;;;12280:30;12346:34;12326:18;;;12319:62;-1:-1:-1;;;12397:18:1;;;12390:33;12440:19;;56581:64:0;12066:399:1;56581:64:0;56746:8;56729:13;;:25;;;;;;;:::i;:::-;;;;-1:-1:-1;;56765:20:0;;;;:7;:20;;;;;:25;;-1:-1:-1;;;;;;56765:25:0;-1:-1:-1;;;;;56765:25:0;;;;;56801:27;;56765:20;56801:14;:27::i;:::-;56955:11;56935:142;56978:22;56992:8;56978:11;:22;:::i;:::-;56968:7;:32;56935:142;;;57032:33;;57057:7;;-1:-1:-1;;;;;57032:33:0;;;57049:1;;57032:33;;57049:1;;57032:33;57002:9;;;;:::i;:::-;;;;56935:142;;77122:149;77185:7;77216:1;77212;:5;:51;;77347:13;77441:15;;;77477:4;77470:15;;;77524:4;77508:21;;77212:51;;;77347:13;77441:15;;;77477:4;77470:15;;;77524:4;77508:21;;77220:20;77279:268;2050:198;2112:5;2168:16;;;;;;;;;;;;;;;;;2224:3;583:64;2186:18;2201:2;2186:14;:18::i;:::-;:33;2185:42;;2168:60;;;;;;;;:::i;:::-;;;;;;;;2050:198;-1:-1:-1;;2050:198:0:o;1293:169::-;1352:7;1385:1;1380:2;:6;1372:15;;;;;;-1:-1:-1;1436:1:0;:6;;;1430:13;;1293:169::o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:173:1;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:70;;177:1;174;167:12;192:160;257:20;;313:13;;306:21;296:32;;286:60;;342:1;339;332:12;357:163;424:20;;484:10;473:22;;463:33;;453:61;;510:1;507;500:12;525:156;591:20;;651:4;640:16;;630:27;;620:55;;671:1;668;661:12;686:186;745:6;798:2;786:9;777:7;773:23;769:32;766:52;;;814:1;811;804:12;766:52;837:29;856:9;837:29;:::i;877:260::-;945:6;953;1006:2;994:9;985:7;981:23;977:32;974:52;;;1022:1;1019;1012:12;974:52;1045:29;1064:9;1045:29;:::i;:::-;1035:39;;1093:38;1127:2;1116:9;1112:18;1093:38;:::i;:::-;1083:48;;877:260;;;;;:::o;1142:328::-;1219:6;1227;1235;1288:2;1276:9;1267:7;1263:23;1259:32;1256:52;;;1304:1;1301;1294:12;1256:52;1327:29;1346:9;1327:29;:::i;:::-;1317:39;;1375:38;1409:2;1398:9;1394:18;1375:38;:::i;:::-;1365:48;;1460:2;1449:9;1445:18;1432:32;1422:42;;1142:328;;;;;:::o;1475:1138::-;1570:6;1578;1586;1594;1647:3;1635:9;1626:7;1622:23;1618:33;1615:53;;;1664:1;1661;1654:12;1615:53;1687:29;1706:9;1687:29;:::i;:::-;1677:39;;1735:38;1769:2;1758:9;1754:18;1735:38;:::i;:::-;1725:48;;1820:2;1809:9;1805:18;1792:32;1782:42;;1875:2;1864:9;1860:18;1847:32;1898:18;1939:2;1931:6;1928:14;1925:34;;;1955:1;1952;1945:12;1925:34;1993:6;1982:9;1978:22;1968:32;;2038:7;2031:4;2027:2;2023:13;2019:27;2009:55;;2060:1;2057;2050:12;2009:55;2096:2;2083:16;2118:2;2114;2111:10;2108:36;;;2124:18;;:::i;:::-;2199:2;2193:9;2167:2;2253:13;;-1:-1:-1;;2249:22:1;;;2273:2;2245:31;2241:40;2229:53;;;2297:18;;;2317:22;;;2294:46;2291:72;;;2343:18;;:::i;:::-;2383:10;2379:2;2372:22;2418:2;2410:6;2403:18;2458:7;2453:2;2448;2444;2440:11;2436:20;2433:33;2430:53;;;2479:1;2476;2469:12;2430:53;2535:2;2530;2526;2522:11;2517:2;2509:6;2505:15;2492:46;2580:1;2575:2;2570;2562:6;2558:15;2554:24;2547:35;2601:6;2591:16;;;;;;;1475:1138;;;;;;;:::o;2618:254::-;2683:6;2691;2744:2;2732:9;2723:7;2719:23;2715:32;2712:52;;;2760:1;2757;2750:12;2712:52;2783:29;2802:9;2783:29;:::i;:::-;2773:39;;2831:35;2862:2;2851:9;2847:18;2831:35;:::i;2877:254::-;2945:6;2953;3006:2;2994:9;2985:7;2981:23;2977:32;2974:52;;;3022:1;3019;3012:12;2974:52;3045:29;3064:9;3045:29;:::i;:::-;3035:39;3121:2;3106:18;;;;3093:32;;-1:-1:-1;;;2877:254:1:o;3136:180::-;3192:6;3245:2;3233:9;3224:7;3220:23;3216:32;3213:52;;;3261:1;3258;3251:12;3213:52;3284:26;3300:9;3284:26;:::i;3321:180::-;3380:6;3433:2;3421:9;3412:7;3408:23;3404:32;3401:52;;;3449:1;3446;3439:12;3401:52;-1:-1:-1;3472:23:1;;3321:180;-1:-1:-1;3321:180:1:o;3506:245::-;3564:6;3617:2;3605:9;3596:7;3592:23;3588:32;3585:52;;;3633:1;3630;3623:12;3585:52;3672:9;3659:23;3691:30;3715:5;3691:30;:::i;3756:249::-;3825:6;3878:2;3866:9;3857:7;3853:23;3849:32;3846:52;;;3894:1;3891;3884:12;3846:52;3926:9;3920:16;3945:30;3969:5;3945:30;:::i;4010:592::-;4081:6;4089;4142:2;4130:9;4121:7;4117:23;4113:32;4110:52;;;4158:1;4155;4148:12;4110:52;4198:9;4185:23;4227:18;4268:2;4260:6;4257:14;4254:34;;;4284:1;4281;4274:12;4254:34;4322:6;4311:9;4307:22;4297:32;;4367:7;4360:4;4356:2;4352:13;4348:27;4338:55;;4389:1;4386;4379:12;4338:55;4429:2;4416:16;4455:2;4447:6;4444:14;4441:34;;;4471:1;4468;4461:12;4441:34;4516:7;4511:2;4502:6;4498:2;4494:15;4490:24;4487:37;4484:57;;;4537:1;4534;4527:12;4484:57;4568:2;4560:11;;;;;4590:6;;-1:-1:-1;4010:592:1;;-1:-1:-1;;;;4010:592:1:o;4792:753::-;4894:6;4902;4910;4918;4971:2;4959:9;4950:7;4946:23;4942:32;4939:52;;;4987:1;4984;4977:12;4939:52;5023:9;5010:23;5000:33;;5084:2;5073:9;5069:18;5056:32;5107:18;5148:2;5140:6;5137:14;5134:34;;;5164:1;5161;5154:12;5134:34;5202:6;5191:9;5187:22;5177:32;;5247:7;5240:4;5236:2;5232:13;5228:27;5218:55;;5269:1;5266;5259:12;5218:55;5309:2;5296:16;5335:2;5327:6;5324:14;5321:34;;;5351:1;5348;5341:12;5321:34;5404:7;5399:2;5389:6;5386:1;5382:14;5378:2;5374:23;5370:32;5367:45;5364:65;;;5425:1;5422;5415:12;5364:65;5456:2;5452;5448:11;5438:21;;5478:6;5468:16;;;;;5503:36;5535:2;5524:9;5520:18;5503:36;:::i;:::-;5493:46;;4792:753;;;;;;;:::o;5550:248::-;5618:6;5626;5679:2;5667:9;5658:7;5654:23;5650:32;5647:52;;;5695:1;5692;5685:12;5647:52;-1:-1:-1;;5718:23:1;;;5788:2;5773:18;;;5760:32;;-1:-1:-1;5550:248:1:o;5803:256::-;5869:6;5877;5930:2;5918:9;5909:7;5905:23;5901:32;5898:52;;;5946:1;5943;5936:12;5898:52;5969:28;5987:9;5969:28;:::i;:::-;5959:38;;6016:37;6049:2;6038:9;6034:18;6016:37;:::i;6064:535::-;6162:6;6170;6178;6186;6194;6202;6255:3;6243:9;6234:7;6230:23;6226:33;6223:53;;;6272:1;6269;6262:12;6223:53;6295:27;6312:9;6295:27;:::i;:::-;6285:37;;6341:36;6373:2;6362:9;6358:18;6341:36;:::i;:::-;6331:46;;6396:37;6429:2;6418:9;6414:18;6396:37;:::i;:::-;6386:47;;6452:37;6485:2;6474:9;6470:18;6452:37;:::i;:::-;6442:47;;6536:3;6525:9;6521:19;6508:33;6498:43;;6588:3;6577:9;6573:19;6560:33;6550:43;;6064:535;;;;;;;;:::o;6604:257::-;6645:3;6683:5;6677:12;6710:6;6705:3;6698:19;6726:63;6782:6;6775:4;6770:3;6766:14;6759:4;6752:5;6748:16;6726:63;:::i;:::-;6843:2;6822:15;-1:-1:-1;;6818:29:1;6809:39;;;;6850:4;6805:50;;6604:257;-1:-1:-1;;6604:257:1:o;7100:637::-;7380:3;7418:6;7412:13;7434:53;7480:6;7475:3;7468:4;7460:6;7456:17;7434:53;:::i;:::-;7550:13;;7509:16;;;;7572:57;7550:13;7509:16;7606:4;7594:17;;7572:57;:::i;:::-;-1:-1:-1;;;7651:20:1;;7680:22;;;7729:1;7718:13;;7100:637;-1:-1:-1;;;;7100:637:1:o;8160:488::-;-1:-1:-1;;;;;8429:15:1;;;8411:34;;8481:15;;8476:2;8461:18;;8454:43;8528:2;8513:18;;8506:34;;;8576:3;8571:2;8556:18;;8549:31;;;8354:4;;8597:45;;8622:19;;8614:6;8597:45;:::i;:::-;8589:53;8160:488;-1:-1:-1;;;;;;8160:488:1:o;8653:632::-;8824:2;8876:21;;;8946:13;;8849:18;;;8968:22;;;8795:4;;8824:2;9047:15;;;;9021:2;9006:18;;;8795:4;9090:169;9104:6;9101:1;9098:13;9090:169;;;9165:13;;9153:26;;9234:15;;;;9199:12;;;;9126:1;9119:9;9090:169;;;-1:-1:-1;9276:3:1;;8653:632;-1:-1:-1;;;;;;8653:632:1:o;9482:219::-;9631:2;9620:9;9613:21;9594:4;9651:44;9691:2;9680:9;9676:18;9668:6;9651:44;:::i;11644:417::-;11846:2;11828:21;;;11885:2;11865:18;;;11858:30;11924:34;11919:2;11904:18;;11897:62;-1:-1:-1;;;11990:2:1;11975:18;;11968:51;12051:3;12036:19;;11644:417::o;14065:416::-;14267:2;14249:21;;;14306:2;14286:18;;;14279:30;14345:34;14340:2;14325:18;;14318:62;-1:-1:-1;;;14411:2:1;14396:18;;14389:50;14471:3;14456:19;;14065:416::o;16744:962::-;17088:4;17117:3;17159:4;17151:6;17147:17;17136:9;17129:36;17213:4;17205:6;17201:17;17196:2;17185:9;17181:18;17174:45;17238:10;17296:2;17288:6;17284:15;17279:2;17268:9;17264:18;17257:43;17348:2;17340:6;17336:15;17331:2;17320:9;17316:18;17309:43;;17389:6;17383:3;17372:9;17368:19;17361:35;17433:6;17427:3;17416:9;17412:19;17405:35;17477:2;17471:3;17460:9;17456:19;17449:31;17503:44;17543:2;17532:9;17528:18;17520:6;17503:44;:::i;:::-;17489:58;;17596:9;17588:6;17584:22;17578:3;17567:9;17563:19;17556:51;17624:32;17649:6;17641;17624:32;:::i;:::-;17616:40;;;17693:6;17687:3;17676:9;17672:19;17665:35;16744:962;;;;;;;;;;;;:::o;17711:128::-;17751:3;17782:1;17778:6;17775:1;17772:13;17769:39;;;17788:18;;:::i;:::-;-1:-1:-1;17824:9:1;;17711:128::o;17844:125::-;17884:4;17912:1;17909;17906:8;17903:34;;;17917:18;;:::i;:::-;-1:-1:-1;17954:9:1;;17844:125::o;17974:258::-;18046:1;18056:113;18070:6;18067:1;18064:13;18056:113;;;18146:11;;;18140:18;18127:11;;;18120:39;18092:2;18085:10;18056:113;;;18187:6;18184:1;18181:13;18178:48;;;-1:-1:-1;;18222:1:1;18204:16;;18197:27;17974:258::o;18237:380::-;18316:1;18312:12;;;;18359;;;18380:61;;18434:4;18426:6;18422:17;18412:27;;18380:61;18487:2;18479:6;18476:14;18456:18;18453:38;18450:161;;;18533:10;18528:3;18524:20;18521:1;18514:31;18568:4;18565:1;18558:15;18596:4;18593:1;18586:15;18450:161;;18237:380;;;:::o;18622:135::-;18661:3;-1:-1:-1;;18682:17:1;;18679:43;;;18702:18;;:::i;:::-;-1:-1:-1;18749:1:1;18738:13;;18622:135::o;18762:127::-;18823:10;18818:3;18814:20;18811:1;18804:31;18854:4;18851:1;18844:15;18878:4;18875:1;18868:15;19026:127;19087:10;19082:3;19078:20;19075:1;19068:31;19118:4;19115:1;19108:15;19142:4;19139:1;19132:15;19158:127;19219:10;19214:3;19210:20;19207:1;19200:31;19250:4;19247:1;19240:15;19274:4;19271:1;19264:15;19290:131;-1:-1:-1;;;;;;19364:32:1;;19354:43;;19344:71;;19411:1;19408;19401:12

Swarm Source

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