ETH Price: $3,219.51 (+3.27%)
 

Overview

ETH Balance

0.015 ETH

Eth Value

$48.29 (@ $3,219.51/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Approval For...215266782025-01-01 2:37:5929 days ago1735699079IN
XXYYZZ: XXYYZZ Token
0 ETH0.000145073.15558855
Set Approval For...198251112024-05-08 11:41:47267 days ago1715168507IN
XXYYZZ: XXYYZZ Token
0 ETH0.000207674.51855083
Set Approval For...188938702023-12-29 21:21:59397 days ago1703884919IN
XXYYZZ: XXYYZZ Token
0 ETH0.0008323618.07729585
Set Approval For...187432152023-12-08 18:05:59418 days ago1702058759IN
XXYYZZ: XXYYZZ Token
0 ETH0.0021774547.3760573
Set Approval For...187377392023-12-07 23:41:23419 days ago1701992483IN
XXYYZZ: XXYYZZ Token
0 ETH0.0024080652.29797814
Set Approval For...187377392023-12-07 23:41:23419 days ago1701992483IN
XXYYZZ: XXYYZZ Token
0 ETH0.0024049252.29797814
Set Approval For...187377382023-12-07 23:41:11419 days ago1701992471IN
XXYYZZ: XXYYZZ Token
0 ETH0.0023638151.43089158
Set Approval For...187289302023-12-06 18:01:23420 days ago1701885683IN
XXYYZZ: XXYYZZ Token
0 ETH0.0036857980.06852452
Set Approval For...187031372023-12-03 3:17:11424 days ago1701573431IN
XXYYZZ: XXYYZZ Token
0 ETH0.0013937930.32561686
Set Approval For...186866102023-11-30 19:50:35426 days ago1701373835IN
XXYYZZ: XXYYZZ Token
0 ETH0.0032914371.61363956
Set Approval For...186836282023-11-30 9:47:59427 days ago1701337679IN
XXYYZZ: XXYYZZ Token
0 ETH0.0012412827.00737214
Set Approval For...186789852023-11-29 18:14:11427 days ago1701281651IN
XXYYZZ: XXYYZZ Token
0 ETH0.0017077737.09884079
Set Approval For...186754002023-11-29 6:12:23428 days ago1701238343IN
XXYYZZ: XXYYZZ Token
0 ETH0.0013480729.28490664
Set Approval For...186753882023-11-29 6:09:47428 days ago1701238187IN
XXYYZZ: XXYYZZ Token
0 ETH0.0007449330.88318888
Safe Transfer Fr...186734832023-11-28 23:45:35428 days ago1701215135IN
XXYYZZ: XXYYZZ Token
0 ETH0.0021952235.60095135
Commit186659532023-11-27 22:28:11429 days ago1701124091IN
XXYYZZ: XXYYZZ Token
0 ETH0.0014547332.97811979
Reroll Specific186656442023-11-27 21:25:47429 days ago1701120347IN
XXYYZZ: XXYYZZ Token
0.00025 ETH0.0017894531.51941326
Commit186656282023-11-27 21:22:35429 days ago1701120155IN
XXYYZZ: XXYYZZ Token
0 ETH0.0015996336.26311516
Reroll Specific186655172023-11-27 21:00:23429 days ago1701118823IN
XXYYZZ: XXYYZZ Token
0.00025 ETH0.0018642532.83006323
Commit186655102023-11-27 20:58:59429 days ago1701118739IN
XXYYZZ: XXYYZZ Token
0 ETH0.0013595730.82087344
Reroll Specific186654872023-11-27 20:54:23429 days ago1701118463IN
XXYYZZ: XXYYZZ Token
0.00025 ETH0.0017837331.4121529
Commit186654802023-11-27 20:52:59429 days ago1701118379IN
XXYYZZ: XXYYZZ Token
0 ETH0.0013157229.83503355
Set Approval For...186651732023-11-27 19:50:59429 days ago1701114659IN
XXYYZZ: XXYYZZ Token
0 ETH0.0019352342.0401536
Approve186651662023-11-27 19:49:35429 days ago1701114575IN
XXYYZZ: XXYYZZ Token
0 ETH0.0020233741.89521223
Set Approval For...186646842023-11-27 18:11:47429 days ago1701108707IN
XXYYZZ: XXYYZZ Token
0 ETH0.0019806243.09370815
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
179938002023-08-25 19:30:23523 days ago1692991823
XXYYZZ: XXYYZZ Token
5.3255 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.015 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.005 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.005 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.005 ETH
175459672023-06-24 0:56:35586 days ago1687568195
XXYYZZ: XXYYZZ Token
0.05 ETH
175459662023-06-24 0:56:23586 days ago1687568183
XXYYZZ: XXYYZZ Token
0.05 ETH
175459662023-06-24 0:56:23586 days ago1687568183
XXYYZZ: XXYYZZ Token
0.005 ETH
175459652023-06-24 0:56:11586 days ago1687568171
XXYYZZ: XXYYZZ Token
0.015 ETH
175459632023-06-24 0:55:47586 days ago1687568147
XXYYZZ: XXYYZZ Token
0.005 ETH
175459632023-06-24 0:55:47586 days ago1687568147
XXYYZZ: XXYYZZ Token
0.005 ETH
175459632023-06-24 0:55:47586 days ago1687568147
XXYYZZ: XXYYZZ Token
0.005 ETH
175459612023-06-24 0:55:23586 days ago1687568123
XXYYZZ: XXYYZZ Token
0.005 ETH
175459612023-06-24 0:55:23586 days ago1687568123
XXYYZZ: XXYYZZ Token
0.025 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
XXYYZZ

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion, MIT license
File 1 of 16 : XXYYZZ.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {XXYYZZMetadata} from "./XXYYZZMetadata.sol";
import {XXYYZZBurn} from "./XXYYZZBurn.sol";
import {XXYYZZSeaDrop} from "./XXYYZZSeaDrop.sol";
import {XXYYZZCore} from "./XXYYZZCore.sol";
import {XXYYZZRerollFinalize} from "./XXYYZZRerollFinalize.sol";
import {XXYYZZCore} from "./XXYYZZCore.sol";
import {LibString} from "solady/utils/LibString.sol";
import {Base64} from "solady/utils/Base64.sol";

/**
 * @title XXYYZZ
 * @author emo.eth
 * @notice XXYYZZ is a collection of fully onchain, collectible colors. Each token has a unique hex value.
 *         Tokens may be "rerolled" to new hex values, unless they are "finalized," in which case, they are immutable.
 *
 *         Finalizing tokens also adds the finalizer's wallet address to the token's metadata.
 *         Tokens may be burned, which removes it from the token supply, but unless the token was finalized, its
 *         particular hex value may be minted or rerolled again.
 *
 *         Mints and rerolls are pseudorandom by default, unless one of the "Specific" methods is called.
 *         To prevent front-running "specific" mint transactions, the XXYYZZ contract uses a commit-reveal scheme.
 *         Users must commit a hash of their desired hex value with a secret salt, wait at least one minute, and then
 *         submit their mint or reroll transaction with the original hex value(s) and salt.
 *         Multiple IDs may be minted or rerolled in a single transaction by committixng the result of hash of all IDs in order
 *         with a single secret salt.
 *         In batch methods, unavailable IDs are skipped, and excess payment is refunded to the caller.
 */
contract XXYYZZ is XXYYZZMetadata, XXYYZZBurn, XXYYZZSeaDrop, XXYYZZRerollFinalize {
    using LibString for uint256;
    using LibString for address;
    using Base64 for bytes;

    constructor(
        address initialOwner,
        address creatorPayout,
        uint256 maxBatchSize,
        uint24[] memory preMintIds,
        address seaDrop
    ) XXYYZZSeaDrop(seaDrop, creatorPayout, initialOwner, maxBatchSize) {
        for (uint256 i; i < preMintIds.length;) {
            _mint(initialOwner, preMintIds[i]);
            _finalizeToken(preMintIds[i], initialOwner);
            unchecked {
                ++i;
            }
        }
        _numMinted = uint32(preMintIds.length);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        pure
        virtual
        override(XXYYZZSeaDrop, XXYYZZCore)
        returns (bool)
    {
        return XXYYZZSeaDrop.supportsInterface(interfaceId);
    }
}

File 2 of 16 : XXYYZZMetadata.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {XXYYZZCore} from "./XXYYZZCore.sol";
import {LibString} from "solady/utils/LibString.sol";
import {Base64} from "solady/utils/Base64.sol";

/**
 * @title XXYYZZMetadata
 * @author emo.eth
 * @notice XXYYZZMetadata implements the onchain metadata for XXYYZZ tokens.
 */
abstract contract XXYYZZMetadata is XXYYZZCore {
    using LibString for uint256;
    using LibString for address;
    using Base64 for bytes;

    /**
     * @notice Return the base64-encoded token metadata. Won't revert if the token doesn't exist.
     *         Will revert if the id is not a valid six-hex-digit ID.
     */
    function tokenURI(uint256 id) public view virtual override returns (string memory) {
        _validateId(id);
        return string.concat("data:application/json;base64,", bytes(_stringURI(id)).encode());
    }

    ///@notice Return the base64-encoded contract-level metadata
    function contractURI() public pure returns (string memory) {
        return string.concat("data:application/json;base64,", bytes(_stringContractURI()).encode());
    }

    ///@dev Return a token-level JSON string
    function _stringURI(uint256 id) internal view virtual returns (string memory) {
        return string.concat(
            "{",
            _kv("name", _name(id)),
            ",",
            _kv("external_link", "https://xxyyzz.art"),
            ",",
            _kv(
                "description",
                "Proof of color. XXYYZZ is a collection of fully onchain, unique, composable, and collectable colors."
            ),
            ",",
            _kv("image", _imageURI(id)),
            ",",
            _kRawV("attributes", _traits(id)),
            "}"
        );
    }

    ///@dev Return a contract-level JSON string
    function _stringContractURI() internal pure returns (string memory) {
        return
        '{"name":"XXYYZZ","description":"Collectible, composable, and unique onchain colors.","external_link":"https://xxyyzz.art"}';
    }

    ///@dev Return a name like "#aabbcc"
    function _name(uint256 id) internal pure returns (string memory) {
        return string.concat("#", id.toHexStringNoPrefix({length: 3}));
    }

    ///@dev Return an svg as a base64-encoded data uri string
    function _imageURI(uint256 id) internal pure returns (string memory) {
        return string.concat("data:image/svg+xml;base64,", bytes(_svg(id)).encode());
    }

    ///@dev Return a 690x690 SVG with a single rect of the token's color
    function _svg(uint256 id) internal pure returns (string memory) {
        return string.concat(
            '<svg xmlns="http://www.w3.org/2000/svg" width="690" height="690"><rect width="690" height="690" fill="#',
            id.toHexStringNoPrefix({length: 3}),
            '" /></svg>'
        );
    }

    ///@dev Return a JSON array of {"trait_type":"key","value":"value"} pairs
    function _traits(uint256 id) internal view returns (string memory) {
        string memory color = _trait("Color", _name(id));
        if (isFinalized(id)) {
            string memory finalizedProp = _trait("Finalized", "Yes");
            return string.concat(
                "[", color, ",", finalizedProp, ",", _trait("Finalizer", finalizers[id].toHexString()), "]"
            );
        } else {
            return string.concat("[", color, ",", _trait("Finalized", "No"), "]");
        }
    }

    ///@dev return a {"trait_type":"key","value":"value"} pair
    function _trait(string memory key, string memory value) internal pure returns (string memory) {
        return string.concat('{"trait_type":"', key, '","value":"', value, '"}');
    }

    ///@dev return a "key":"value" pair
    function _kv(string memory key, string memory value) internal pure returns (string memory) {
        return string.concat('"', key, '":"', value, '"');
    }

    ///@dev Return a "key":value pair without quoting value
    function _kRawV(string memory key, string memory value) internal pure returns (string memory) {
        return string.concat('"', key, '":', value);
    }
}

File 3 of 16 : XXYYZZBurn.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {XXYYZZCore} from "./XXYYZZCore.sol";

abstract contract XXYYZZBurn is XXYYZZCore {
    //////////
    // BURN //
    //////////

    /**
     * @notice Permanently burn a token that the caller owns or is approved for.
     * @param xxyyzz The token to burn.
     * @param onlyFinalized If true, only tokens that have been finalized can be burned. Useful if an approved operator
     *                      is burning tokens on behalf of a user.
     */
    function burn(uint256 xxyyzz, bool onlyFinalized) public {
        // cannot overflow as there are at most 2^24 tokens, and _numBurned is a uint32
        unchecked {
            _numBurned += 1;
        }
        if (onlyFinalized) {
            if (!_isFinalized(xxyyzz)) {
                revert OnlyFinalized();
            }
        }
        _burn(msg.sender, xxyyzz);
    }

    /**
     * @notice Permanently burn multiple tokens. All must be owned by the same address.
     * @param ids The tokens to burn.
     * @param onlyFinalized If true, only tokens that have been finalized can be burned. Useful if an approved operator
     *                      is burning tokens on behalf of a user.
     */
    function batchBurn(uint256[] calldata ids, bool onlyFinalized) public {
        if (ids.length == 0) {
            revert NoIdsProvided();
        }
        uint256 packedOwnerFinalizedSlot = _packedOwnershipSlot(ids[0]);
        address initialTokenOwner = address(uint160(packedOwnerFinalizedSlot));
        if (onlyFinalized) {
            if (packedOwnerFinalizedSlot < type(uint160).max) {
                revert OnlyFinalized();
            }
        }
        // validate that msg.sender has approval to burn all tokens
        if (initialTokenOwner != msg.sender) {
            if (!isApprovedForAll(initialTokenOwner, msg.sender)) {
                revert BatchBurnerNotApprovedForAll();
            }
        }
        // safe because there are at most 2^24 tokens, and ownerships are checked
        unchecked {
            _numBurned += uint32(ids.length);
        }
        _burn(ids[0]);
        for (uint256 i = 1; i < ids.length;) {
            uint256 id = ids[i];
            packedOwnerFinalizedSlot = _packedOwnershipSlot(id);
            address owner = address(uint160(packedOwnerFinalizedSlot));
            // ensure that all tokens are owned by the same address
            if (owner != initialTokenOwner) {
                revert OwnerMismatch();
            }
            if (onlyFinalized) {
                if (packedOwnerFinalizedSlot < type(uint160).max) {
                    revert OnlyFinalized();
                }
            }
            // no need to specify msg.sender since caller is approved for all tokens
            // this also checks token exists
            _burn(id);
            unchecked {
                ++i;
            }
        }
    }
}

File 4 of 16 : XXYYZZSeaDrop.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {XXYYZZMint} from "./XXYYZZMint.sol";
import {ISeaDrop, PublicDrop} from "./lib/SeaDropSpecific.sol";

abstract contract XXYYZZSeaDrop is XXYYZZMint {
    error OnlySeadrop();

    address immutable SEADROP;
    address immutable CREATOR_PAYOUT;
    uint256 immutable DEPLOYED_TIME;

    uint256 private constant SEADROP_TOKEN_CREATED_EVENT_TOPIC =
        0xd7aca75208b9be5ffc04c6a01922020ffd62b55e68e502e317f5344960279af8;
    address private constant SEADROP_FEE_RECIPIENT = 0x0000a26b00c1F0DF003000390027140000fAa719;
    address private constant SEADROP_ALLOWED_PAYER_1 = 0xf408Bee3443D0397e2c1cdE588Fb060AC657006F;
    address private constant SEADROP_ALLOWED_PAYER_2 = 0xE3d3D0eD702504e19825f44BC6542Ff2ec45cB9A;
    uint256 private constant INONFUNGIBLESEADROP_INTERFACE_ID = 0x1890fe8e;

    constructor(address seadrop, address creatorPayout, address initialOwner, uint256 maxBatchSize)
        XXYYZZMint(initialOwner, maxBatchSize)
    {
        SEADROP = seadrop;
        DEPLOYED_TIME = block.timestamp;
        CREATOR_PAYOUT = creatorPayout;

        // log without adding event to abi
        assembly {
            log1(0, 0, SEADROP_TOKEN_CREATED_EVENT_TOPIC)
        }
    }

    /**
     * @notice Configure the SeaDrop contract. onlyOwner.
     * @dev SeaDrop calls supportsInterface, so this unfortunately can't live in the constructor.
     */
    function configureSeaDrop() external onlyOwner {
        ISeaDrop seadrop = ISeaDrop(SEADROP);
        seadrop.updatePublicDrop(
            PublicDrop({
                mintPrice: uint80(0.005 ether),
                startTime: uint48(DEPLOYED_TIME),
                endTime: uint48(MAX_MINT_CLOSE_TIMESTAMP),
                maxTotalMintableByWallet: type(uint16).max,
                feeBps: uint16(1000),
                restrictFeeRecipients: true
            })
        );
        seadrop.updateCreatorPayoutAddress(CREATOR_PAYOUT);
        seadrop.updateAllowedFeeRecipient(SEADROP_FEE_RECIPIENT, true);
        seadrop.updatePayer(SEADROP_ALLOWED_PAYER_1, true);
        seadrop.updatePayer(SEADROP_ALLOWED_PAYER_2, true);
    }

    function mintSeaDrop(address recipient, uint256 quantity) external {
        if (msg.sender != SEADROP) {
            revert OnlySeadrop();
        }
        // increment supply before minting
        uint128 newAmount;
        // this can be unchecked because an ID can only be minted once, and all IDs are later validated to be uint24s
        unchecked {
            newAmount = _numMinted + uint128(quantity);
        }
        _numMinted = newAmount;
        _mintTo(recipient, quantity, newAmount);
    }

    /**
     * @dev See {IERC165-supportsInterface}. Overridden to support SeaDrop.
     */
    function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool result) {
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. ERC4906: 0x49064906
            result :=
                or(
                    or(or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)), eq(s, 0x49064906)),
                    eq(s, INONFUNGIBLESEADROP_INTERFACE_ID)
                )
        }
    }

    /**
     * @dev Hard-coded for SeaDrop support
     */
    function getMintStats(address) external view returns (uint256, uint256, uint256) {
        return (0, _numMinted, 16777216);
    }

    /**
     * @dev Hard-coded for SeaDrop support
     */
    function maxSupply() external pure returns (uint256) {
        return 16777216;
    }
}

File 5 of 16 : XXYYZZCore.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {ERC721} from "solady/tokens/ERC721.sol";
import {CommitReveal} from "./lib/CommitReveal.sol";
import {Ownable} from "solady/auth/Ownable.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {IERC4906, IERC165} from "./interfaces/IERC4906.sol";

/**
 * @title XXYYZZCore
 * @author emo.eth
 * @notice Core contract for XXYYZZ NFTs. Contains errors, constants, core token information, and helper functions.
 */
abstract contract XXYYZZCore is ERC721, IERC4906, CommitReveal, Ownable {
    error InvalidPayment();
    error InvalidHex();
    error MaximumSupplyExceeded();
    error AlreadyFinalized();
    error OnlyTokenOwner();
    error NoIdsProvided();
    error OwnerMismatch();
    error BatchBurnerNotApprovedForAll();
    error ArrayLengthMismatch();
    error MintClosed();
    error InvalidTimestamp();
    error OnlyFinalized();
    error Unavailable();
    error NoneAvailable();
    error MaxBatchSizeExceeded();

    uint256 public constant MINT_PRICE = 0.005 ether;
    uint256 public constant REROLL_PRICE = 0.00025 ether;
    uint256 public constant FINALIZE_PRICE = 0.005 ether;
    uint256 public constant REROLL_AND_FINALIZE_PRICE = 0.00525 ether;
    uint256 public immutable MAX_SPECIFIC_BATCH_SIZE;

    uint256 constant BYTES3_UINT_SHIFT = 232;
    uint256 constant MAX_UINT24 = 0xFFFFFF;
    uint96 constant FINALIZED = 1;
    uint96 constant NOT_FINALIZED = 0;

    // re-declared from solady ERC721 for custom gas optimizations
    uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192;

    mapping(uint256 tokenId => address finalizer) public finalizers;
    uint128 _numBurned;
    uint128 _numMinted;

    constructor(address initialOwner, uint256 maxBatchSize)
        // lifespan
        CommitReveal(
            1 days,
            // delay – MM/RPC will report a tx will revert until first eligible block is validated,
            // so 48 seconds will result in 60 seconds of delay before the frontend will report
            // that a tx will succeed
            48 seconds
        )
    {
        _initializeOwner(initialOwner);
        MAX_SPECIFIC_BATCH_SIZE = maxBatchSize;
    }

    receive() external payable {
        // send ether – see what happens! :)
    }

    ///////////////////
    // OWNER METHODS //
    ///////////////////

    /**
     * @notice Withdraws all funds from the contract to the current owner. onlyOwner.
     */
    function withdraw() public onlyOwner {
        assembly ("memory-safe") {
            let succ := call(gas(), caller(), selfbalance(), 0, 0, 0, 0)
            // revert with returndata if call failed
            if iszero(succ) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }
        }
    }

    ///////////////////
    // INFORMATIONAL //
    ///////////////////

    /**
     * @notice Get the total number of tokens in circulation
     */
    function totalSupply() public view returns (uint256) {
        return _numMinted - _numBurned;
    }

    /**
     * @notice Get the total number of tokens minted
     */
    function numMinted() external view returns (uint256) {
        return _numMinted;
    }

    /**
     * @notice Get the total number of tokens burned
     */
    function numBurned() external view returns (uint256) {
        return _numBurned;
    }

    /**
     * @notice Get the name of the token
     */
    function name() public pure override returns (string memory) {
        // note that this is unsafe to call internally, as it abi-encodes the name and
        // performs a low-level return
        assembly {
            mstore(0x20, 0x20)
            mstore(0x46, 0x06585859595a5a)
            return(0x20, 0x80)
        }
    }

    /**
     * @notice Get the symbol of the token
     */
    function symbol() public pure override returns (string memory) {
        // note that this is unsafe to call internally, as it abi-encodes the symbol and
        // performs a low-level return
        assembly {
            mstore(0x20, 0x20)
            mstore(0x46, 0x06585859595a5a)
            return(0x20, 0x80)
        }
    }

    /**
     * @notice Check if a specific token ID has been finalized. Will return true for tokens that were finalized and
     *         then burned. Will not revert if the tokenID does not currently exist. Will revert on invalid tokenIds.
     * @param id The token ID to check
     * @return True if the token ID has been finalized, false otherwise
     */
    function isFinalized(uint256 id) public view returns (bool) {
        _validateId(id);
        return _isFinalized(id);
    }

    ///@inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId)
        public
        pure
        virtual
        override(ERC721, IERC165)
        returns (bool result)
    {
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. ERC4906: 0x49064906
            result := or(or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)), eq(s, 0x49064906))
        }
    }

    /////////////////
    // COMMITMENTS //
    /////////////////

    /**
     * @notice Get a commitment hash for a given sender, tokenId, and salt. Note that this could expose your desired
     *         ID to the RPC provider. Won't revert if the ID is invalid, but will return an invalid hash.
     * @param sender The address of the account that will mint or reroll the token ID
     * @param id The 6-hex-digit token ID to mint or reroll
     * @param salt The salt to use for the commitment
     */
    function computeCommitment(address sender, uint256 id, bytes32 salt)
        public
        pure
        returns (bytes32 committmentHash)
    {
        assembly ("memory-safe") {
            // shift sender left by 24 bits; id stays in bottom 24
            mstore(0, or(shl(24, sender), and(id, MAX_UINT24)))
            mstore(0x20, salt)
            // start hashing at 0x09 to skip 9 empty bytes (32 - (20 + 3))
            committmentHash := keccak256(0x09, 0x40)
        }
    }

    /**
     * @notice Get a commitment hash for a given sender, array of tokenIds, and salt. This allows for a single
     *         commitment for a batch of IDs, but note that order and length of IDs matters.
     *         If 5 IDs are passed, all 5 must be passed to either batchMintSpecific or batchRerollSpecific, in the
     *         same order. Note that this could expose your desired IDs to the RPC provider.
     *         Won't revert if any IDs are invalid or duplicated.
     * @param sender The address of the account that will mint or reroll the token IDs
     * @param ids The 6-hex-digit token IDs to mint or reroll
     * @param salt The salt to use for the batch commitment
     */
    function computeBatchCommitment(address sender, uint256[] calldata ids, bytes32 salt)
        public
        pure
        returns (bytes32 commitmentHash)
    {
        assembly ("memory-safe") {
            // cache free mem pointer
            let freeMemPtr := mload(0x40)
            // multiply length of elements by 32 bytes for each element
            let numBytes := shl(5, ids.length)
            // copy contents of array to unallocated free memory
            calldatacopy(freeMemPtr, ids.offset, numBytes)
            // hash contents of array, without length
            let arrayHash :=
                keccak256(
                    // start of array contents
                    freeMemPtr,
                    //length of array contents
                    numBytes
                )

            // store sender in first memory slot
            mstore(0, sender)
            // store array hash in second memory slot
            mstore(0x20, arrayHash)
            // clobber free memory pointer with salt
            mstore(0x40, salt)
            // compute commitment hash
            // start hashing at 12 bytes since addresses are 20 bytes
            commitmentHash := keccak256(0x0c, 0x60)
            // restore free memory pointer
            mstore(0x40, freeMemPtr)
        }
    }

    /////////////
    // HELPERS //
    /////////////

    /**
     * @dev Mint a token with a specific hex value and validate it was committed to
     * @param id The 6-hex-digit token ID to mint
     * @param salt The salt to use for the commitment
     */
    function _mintSpecific(uint256 id, bytes32 salt) internal {
        bytes32 computedCommitment = computeCommitment(msg.sender, id, salt);

        // validate ID is valid 6-hex-digit number
        _validateId(id);
        // validate commitment to prevent front-running
        _assertCommittedReveal(computedCommitment);

        // don't allow minting of tokens that were finalized and then burned
        if (_isFinalized(id)) {
            revert AlreadyFinalized();
        }
        _mint(msg.sender, id);
    }

    /**
     * @dev Mint a token with a specific hex value and validate it was committed to
     * @param id The 6-hex-digit token ID to mint
     * @param computedCommitment The commitment hash to validate
     */
    function _mintSpecificWithCommitment(uint256 id, bytes32 computedCommitment) internal {
        // validate ID is valid 6-hex-digit number
        _validateId(id);
        // validate commitment to prevent front-running
        _assertCommittedReveal(computedCommitment);

        // don't allow minting of tokens that were finalized and then burned
        if (_packedOwnershipSlot(id) != 0) {
            revert AlreadyFinalized();
        }
        _mint(msg.sender, id);
    }

    /**
     * @dev Mint a token with a specific hex value without validating it was committed to
     * @param id The 6-hex-digit token ID to mint
     * @return True if the token was minted, false otherwise
     */
    function _mintSpecificUnprotected(uint256 id) internal returns (bool) {
        // validate ID is valid 6-hex-digit number
        _validateId(id);
        // don't allow minting of tokens that exist or were finalized and then burned
        if (_packedOwnershipSlot(id) != 0) {
            // return false indicating a no-op
            return false;
        }
        // otherwise mint the token
        _mint(msg.sender, id);
        return true;
    }

    /**
     * @dev Find the first unminted token ID based on the current number minted and PREVRANDAO
     * @param seed The seed to use for the random number generation – when minting, should be _numMinted, when
     *             re-rolling, should be a function of the caller. In the case of re-rolling, this means that if a single caller makes
     *             multiple re-rolls in the same block, there will be collisions. This is fine, as the extra gas  cost
     *             discourages batch re-rolling with bots or scripts (at least from the same address).
     */
    function _findAvailableHex(uint256 seed) internal view returns (uint256) {
        uint256 tokenId;
        assembly {
            mstore(0, seed)
            mstore(0x20, prevrandao())
            // hash the two values together and then mask to a uint24
            // seed is max an address, so start hashing at 0x0c
            tokenId := and(keccak256(0x0c, 0x40), MAX_UINT24)
        }
        // check for the small chance that the token ID is already minted or finalized – if so, increment until we
        // find one that isn't
        while (_packedOwnershipSlot(tokenId) != 0) {
            // safe to do unchecked math here as it is modulo 2^24
            unchecked {
                tokenId = (tokenId + 1) & MAX_UINT24;
            }
        }
        return tokenId;
    }

    ///@dev Check if an ID is a valid six-hex-digit number
    function _validateId(uint256 xxyyzz) internal pure {
        if (xxyyzz > MAX_UINT24) {
            revert InvalidHex();
        }
    }

    ///@dev Validate msg value is equal to total price
    function _validatePayment(uint256 unitPrice, uint256 quantity) internal view {
        // can't overflow because there are at most uint24 tokens, and existence is checked for each token down the line
        unchecked {
            if (msg.value != (unitPrice * quantity)) {
                revert InvalidPayment();
            }
        }
    }

    /**
     * @dev Refund any overpayment
     * @param unitPrice The price per action (mint, reroll, reroll+finalize)
     * @param availableQuantity The number of tokens (mints, rerolls) that were actually available for purchase
     */
    function _refundOverpayment(uint256 unitPrice, uint256 availableQuantity) internal {
        unchecked {
            // can't underflow because payment was already validated; even if it did, value would be larger than ether
            // supply
            uint256 overpayment = msg.value - (unitPrice * availableQuantity);
            if (overpayment != 0) {
                SafeTransferLib.safeTransferETH(msg.sender, overpayment);
            }
        }
    }

    /**
     * @dev Check if a specific token has been finalized. Does not check if token exists.
     * @param id The 6-hex-digit token ID to check
     */
    function _isFinalized(uint256 id) internal view returns (bool) {
        return _getExtraData(id) == FINALIZED;
    }

    /**
     * @dev Load the raw ownership slot for a given token ID, which contains both the owner and the extra data
     *      (finalization status). This allows for succint checking of whether or not a token is mintable,
     *      i.e., whether it does not currently exist and has not been finalized. It also allows for avoiding
     *      an extra SLOAD in cases when checking both owner/existence and finalization status.
     * @param id The 6-hex-digit token ID to check
     */
    function _packedOwnershipSlot(uint256 id) internal view returns (uint256 result) {
        assembly {
            // since all ids are < uint24, this basically just clears the 0-slot before writing 4 bytes of slot seed
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := sload(add(id, add(id, keccak256(0x00, 0x20))))
        }
    }

    function _checkCallerIsOwnerAndNotFinalized(uint256 id) internal view {
        uint256 packedSlot = _packedOwnershipSlot(id);
        // clean and cast to address
        address owner = address(uint160(packedSlot));
        if ((packedSlot) > type(uint160).max) {
            revert AlreadyFinalized();
        }
        // check that caller is owner
        if (owner != msg.sender) {
            revert OnlyTokenOwner();
        }
    }

    /**
     * @dev Check that array lengths match, the batch size is not too large, and that the payment is correct
     * @param a The first array to check
     * @param b The second array to check
     * @param unitPrice The price per action (mint, reroll, reroll+finalize)
     */
    function _validateRerollBatchAndPayment(uint256[] calldata a, uint256[] calldata b, uint256 unitPrice)
        internal
        view
    {
        if (a.length != b.length) {
            revert ArrayLengthMismatch();
        }
        if (a.length > MAX_SPECIFIC_BATCH_SIZE) {
            revert MaxBatchSizeExceeded();
        }
        _validatePayment(a.length, unitPrice);
    }
}

File 6 of 16 : XXYYZZRerollFinalize.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {XXYYZZCore} from "./XXYYZZCore.sol";

/**
 * @title XXYYZZRerollFinalize
 * @author emo.eth
 * @notice This contract handles "rerolling" and "finalizing" tokens.
 *         Rerolling allows users to burn a token they own in exchange for a new one. The new token may be either
 *         pseudorandom, or a specific color when using one of the "Specific" methods.
 *         Finalizing allows users to prevent a token from being rerolled again, in addition to adding their
 *         wallet address to the token's metadata as the "Finalizer" trait.
 */
abstract contract XXYYZZRerollFinalize is XXYYZZCore {
    ////////////
    // REROLL //
    ////////////
    /**
     * @notice Burn a token you own and mint a new one with a pseudorandom hex value.
     * @param oldId The 6-hex-digit token ID to burn
     * @return The new token ID
     */
    function reroll(uint256 oldId) public payable returns (uint256) {
        _validatePayment(REROLL_PRICE, 1);
        // use the caller as the seed to derive the new token ID
        // this means multiple calls in the same block will be gas-inefficient
        // which may somewhat discourage botting
        return _rerollWithSeed(oldId, uint160(msg.sender));
    }

    /**
     * @notice Burn a number of tokens you own and mint new ones with pseudorandom hex values.
     * @param ids The 6-hex-digit token IDs to burn in exchange for new tokens
     * @return The new token IDs
     */
    function batchReroll(uint256[] calldata ids) public payable returns (uint256[] memory) {
        _validatePayment(REROLL_PRICE, ids.length);
        // use the caller as the seed to derive the new token IDs
        // this means multiple calls in the same block will be gas-inefficient
        // which may somewhat discourage botting
        uint256 seed = uint256(uint160(msg.sender));
        uint256[] memory newIds = new uint256[](ids.length);
        for (uint256 i; i < ids.length;) {
            newIds[i] = _rerollWithSeed(ids[i], seed);
            unchecked {
                ++i;
                ++seed;
            }
        }
        return newIds;
    }

    /**
     * @notice Burn and re-mint a token with a specific hex ID. Uses a commit-reveal scheme to prevent front-running.
     *         Only callable by the owner of the token. Users must call `commit(bytes32)` with the result of
     *         `computeCommitment(address,uint256,bytes32)` and wait at least COMMITMENT_LIFESPAN seconds before
     *         calling `rerollSpecific`.
     * @param oldId The 6-hex-digit token ID to burn
     * @param newId The 6-hex-digit token ID to mint
     * @param salt The salt used in the commitment for the new ID commitment
     */
    function rerollSpecific(uint256 oldId, uint256 newId, bytes32 salt) public payable {
        _validatePayment(REROLL_PRICE, 1);
        _rerollSpecificWithSalt(oldId, newId, salt);
    }

    /**
     * @notice Burn and re-mint a number of tokens with specific hex values. Uses a commit-reveal scheme to prevent
     *         front-running. Only callable by the owner of the tokens. Users must call `commit(bytes32)` with the
     *         result of `computeBatchCommitment(address,uint256[],bytes32)` and wait at least COMMITMENT_LIFESPAN
     *         seconds before calling `batchRerollSpecific`.
     * @param oldIds The 6-hex-digit token IDs to burn
     * @param newIds The 6-hex-digit token IDs to mint
     * @param salt The salt used in the commitment for the new IDs commitment
     * @return An array of booleans indicating whether each token was successfully rerolled
     */
    function batchRerollSpecific(uint256[] calldata oldIds, uint256[] calldata newIds, bytes32 salt)
        public
        payable
        returns (bool[] memory)
    {
        _validateRerollBatchAndPayment(oldIds, newIds, REROLL_PRICE);
        bytes32 computedCommitment = computeBatchCommitment(msg.sender, newIds, salt);
        _assertCommittedReveal(computedCommitment);

        return _batchRerollAndRefund(oldIds, newIds);
    }

    /**
     * @notice Burn and re-mint a token with a specific hex ID, then finalize it. Uses a commit-reveal scheme to
     *         prevent front-running. Only callable by the owner of the token. Users must call `commit(bytes32)`
     *         with the result of `computeCommitment(address,uint256,bytes32)` and wait at least COMMITMENT_LIFESPAN
     *         seconds before calling `rerollSpecificAndFinalize`.
     * @param oldId The 6-hex-digit token ID to burn
     * @param newId The 6-hex-digit token ID to mint
     * @param salt The salt used in the commitment for the new ID commitment
     */
    function rerollSpecificAndFinalize(uint256 oldId, uint256 newId, bytes32 salt) public payable {
        _validatePayment(REROLL_AND_FINALIZE_PRICE, 1);

        _rerollSpecificWithSalt(oldId, newId, salt);
        // won't re-validate price, but above function already did
        _finalizeToken(newId, msg.sender);
    }

    /**
     * @notice Burn and re-mint a number of tokens with specific hex values, then finalize them.
     * @param oldIds The 6-hex-digit token IDs to burn
     * @param newIds The 6-hex-digit token IDs to mint
     * @param salt The salt used in the batch commitment for the new ID commitment
     * @return An array of booleans indicating whether each token was successfully rerolled
     */
    function batchRerollSpecificAndFinalize(uint256[] calldata oldIds, uint256[] calldata newIds, bytes32 salt)
        public
        payable
        returns (bool[] memory)
    {
        _validateRerollBatchAndPayment(oldIds, newIds, REROLL_AND_FINALIZE_PRICE);
        bytes32 computedCommitment = computeBatchCommitment(msg.sender, newIds, salt);
        _assertCommittedReveal(computedCommitment);
        return _batchRerollAndFinalizeAndRefund(oldIds, newIds);
    }

    //////////////
    // FINALIZE //
    //////////////

    /**
     * @notice Finalize a token, which updates its metadata with a "Finalizer" trait and prevents it from being
     *         rerolled in the future.
     * @param id The 6-hex-digit token ID to finalize. Must be owned by the caller.
     */
    function finalize(uint256 id) public payable {
        _validatePayment(FINALIZE_PRICE, 1);
        _finalize(id);
    }

    /**
     * @notice Finalize a number of tokens, which updates their metadata with a "Finalizer" trait and prevents them
     *         from being rerolled in the future. The caller must pay the finalization price for each token, and must
     *         own all tokens.
     * @param ids The 6-hex-digit token IDs to finalize
     */
    function batchFinalize(uint256[] calldata ids) public payable {
        _validatePayment(FINALIZE_PRICE, ids.length);
        for (uint256 i; i < ids.length;) {
            _finalize(ids[i]);
            unchecked {
                ++i;
            }
        }
    }

    //////////////
    // INTERNAL //
    //////////////

    /**
     * @dev Internal function to burn and re-mint tokens with a specific hex ID. Does not check initial payment.
     *      Does refund any overpayment.
     * @param oldIds The 6-hex-digit token IDs to burn
     * @param newIds The 6-hex-digit token IDs to mint
     * @return An array of booleans indicating whether each token was successfully rerolled
     */
    function _batchRerollAndRefund(uint256[] calldata oldIds, uint256[] calldata newIds)
        internal
        returns (bool[] memory)
    {
        bool[] memory rerolled = new bool[](oldIds.length);
        uint256 quantityRerolled;
        for (uint256 i; i < oldIds.length;) {
            if (_rerollSpecificUnprotected(oldIds[i], newIds[i])) {
                rerolled[i] = true;
                unchecked {
                    ++quantityRerolled;
                }
            }
            unchecked {
                ++i;
            }
        }
        // if none were rerolled, revert to avoid wasting further gas
        if (quantityRerolled == 0) {
            revert NoneAvailable();
        }
        // refund any overpayment
        _refundOverpayment(REROLL_PRICE, quantityRerolled);

        return rerolled;
    }

    /**
     * @dev Internal function to burn and re-mint tokens with a specific hex ID, then finalize them. Does not check
     *     initial payment. Does refund any overpayment.
     * @param oldIds The 6-hex-digit token IDs to burn
     * @param newIds The 6-hex-digit token IDs to mint
     * @return An array of booleans indicating whether each token was successfully rerolled
     */
    function _batchRerollAndFinalizeAndRefund(uint256[] calldata oldIds, uint256[] calldata newIds)
        internal
        returns (bool[] memory)
    {
        bool[] memory rerolled = new bool[](oldIds.length);
        uint256 quantityRerolled;
        for (uint256 i; i < oldIds.length;) {
            if (_rerollSpecificUnprotected(oldIds[i], newIds[i])) {
                _finalizeToken(newIds[i], msg.sender);
                rerolled[i] = true;
                unchecked {
                    ++quantityRerolled;
                }
            }
            unchecked {
                ++i;
            }
        }
        // if none were rerolled, revert to avoid wasting gas
        if (quantityRerolled == 0) {
            revert NoneAvailable();
        }
        // refund any overpayment
        _refundOverpayment(REROLL_AND_FINALIZE_PRICE, quantityRerolled);

        return rerolled;
    }

    /**
     * @dev Validate an old tokenId is rerollable, burn it, then mint a token with a pseudorandom
     *      hex ID.
     * @param oldId The old ID to reroll
     * @param seed The seed to use for the reroll
     *
     */
    function _rerollWithSeed(uint256 oldId, uint256 seed) internal returns (uint256) {
        _checkCallerIsOwnerAndNotFinalized(oldId);
        // burn old token
        _burn(oldId);
        uint256 tokenId = _findAvailableHex(seed);
        _mint(msg.sender, tokenId);
        return tokenId;
    }

    /**
     * @dev Validate an old tokenId is rerollable, burn it, then mint a token with a specific
     *     hex ID, validating that the commit-reveal scheme was followed.
     * @param oldId The old ID to reroll
     * @param newId The new ID to mint
     * @param salt The salt used in the commit-reveal scheme
     */
    function _rerollSpecificWithSalt(uint256 oldId, uint256 newId, bytes32 salt) internal {
        _checkCallerIsOwnerAndNotFinalized(oldId);
        // burn old token
        _burn(oldId);
        _mintSpecific(newId, salt);
    }

    /**
     * @dev Validate an old tokenId is rerollable, mint a token with a specific new hex ID (if available)
     *      and burn the old token.
     * @param oldId The old ID to reroll
     * @param newId The new ID to mint
     * @return Whether the mint succeeded, ie, the new ID was available
     */
    function _rerollSpecificUnprotected(uint256 oldId, uint256 newId) internal returns (bool) {
        _checkCallerIsOwnerAndNotFinalized(oldId);
        // only burn old token if mint succeeded
        if (_mintSpecificUnprotected(newId)) {
            _burn(oldId);
            return true;
        }
        return false;
    }

    /**
     * @dev Internal function to finalize a token, first checking that the caller is the owner and that the token
     *      has not already been finalized.
     * @param id The 6-hex-digit token ID to finalize
     */
    function _finalize(uint256 id) internal {
        _checkCallerIsOwnerAndNotFinalized(id);
        // set finalized flag
        _finalizeToken(id, msg.sender);
        // emit onchain metadata update event
        emit MetadataUpdate(id);
    }

    /**
     * @dev Finalize a tokenId, updating its metadata with a "Finalizer" trait, and preventing it from being rerolled in the future.
     * @param id The 6-hex-digit token ID to finalize
     * @param finalizer The address of the account finalizing the token
     */
    function _finalizeToken(uint256 id, address finalizer) internal {
        finalizers[id] = finalizer;
        _setExtraData(id, 1);
    }
}

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

/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
library LibString {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The `length` of the output is too small to contain all the hex digits.
    error HexLengthInsufficient();

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

    /// @dev The constant returned when the `search` is not found in the string.
    uint256 internal constant NOT_FOUND = type(uint256).max;

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

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(uint256 value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits.
            str := add(mload(0x40), 0x80)
            // Update the free memory pointer to allocate.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

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

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

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

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(int256 value) internal pure returns (string memory str) {
        if (value >= 0) {
            return toString(uint256(value));
        }
        unchecked {
            str = toString(uint256(-value));
        }
        /// @solidity memory-safe-assembly
        assembly {
            // We still have some spare memory space on the left,
            // as we have allocated 3 words (96 bytes) for up to 78 digits.
            let length := mload(str) // Load the string length.
            mstore(str, 0x2d) // Store the '-' character.
            str := sub(str, 1) // Move back the string pointer by a byte.
            mstore(str, add(length, 1)) // Update the string length.
        }
    }

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

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2 + 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value, length);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexStringNoPrefix(uint256 value, uint256 length)
        internal
        pure
        returns (string memory str)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes
            // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
            // We add 0x20 to the total and round down to a multiple of 0x20.
            // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
            str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
            // Allocate the memory.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let start := sub(str, add(length, length))
            let w := not(1) // Tsk.
            let temp := value
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for {} 1 {} {
                str := add(str, w) // `sub(str, 2)`.
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(xor(str, start)) { break }
            }

            if temp {
                // Store the function selector of `HexLengthInsufficient()`.
                mstore(0x00, 0x2194895a)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2 + 2` bytes.
    function toHexString(uint256 value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2` bytes.
    function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x40 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
            str := add(mload(0x40), 0x80)
            // Allocate the memory.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let w := not(1) // Tsk.
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for { let temp := value } 1 {} {
                str := add(str, w) // `sub(str, 2)`.
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(temp) { break }
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
    /// and the alphabets are capitalized conditionally according to
    /// https://eips.ethereum.org/EIPS/eip-55
    function toHexStringChecksumed(address value) internal pure returns (string memory str) {
        str = toHexString(value);
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
            let o := add(str, 0x22)
            let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
            let t := shl(240, 136) // `0b10001000 << 240`
            for { let i := 0 } 1 {} {
                mstore(add(i, i), mul(t, byte(i, hashed)))
                i := add(i, 1)
                if eq(i, 20) { break }
            }
            mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
            o := add(o, 0x20)
            mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    function toHexString(address value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexStringNoPrefix(address value) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            str := mload(0x40)

            // Allocate the memory.
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x28 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
            mstore(0x40, add(str, 0x80))

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            str := add(str, 2)
            mstore(str, 40)

            let o := add(str, 0x20)
            mstore(add(o, 40), 0)

            value := shl(96, value)

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for { let i := 0 } 1 {} {
                let p := add(o, add(i, i))
                let temp := byte(i, value)
                mstore8(add(p, 1), mload(and(temp, 15)))
                mstore8(p, mload(shr(4, temp)))
                i := add(i, 1)
                if eq(i, 20) { break }
            }
        }
    }

    /// @dev Returns the hex encoded string from the raw bytes.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexString(bytes memory raw) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(raw);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hex encoded string from the raw bytes.
    /// The output is encoded using 2 hexadecimal digits per byte.
    function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {
        /// @solidity memory-safe-assembly
        assembly {
            let length := mload(raw)
            str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
            mstore(str, add(length, length)) // Store the length of the output.

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let o := add(str, 0x20)
            let end := add(raw, length)

            for {} iszero(eq(raw, end)) {} {
                raw := add(raw, 1)
                mstore8(add(o, 1), mload(and(mload(raw), 15)))
                mstore8(o, mload(and(shr(4, mload(raw)), 15)))
                o := add(o, 2)
            }
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(0x40, add(o, 0x20)) // Allocate the memory.
        }
    }

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

    /// @dev Returns the number of UTF characters in the string.
    function runeCount(string memory s) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(s) {
                mstore(0x00, div(not(0), 255))
                mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
                let o := add(s, 0x20)
                let end := add(o, mload(s))
                for { result := 1 } 1 { result := add(result, 1) } {
                    o := add(o, byte(0, mload(shr(250, mload(o)))))
                    if iszero(lt(o, end)) { break }
                }
            }
        }
    }

    /// @dev Returns if this string is a 7-bit ASCII string.
    /// (i.e. all characters codes are in [0..127])
    function is7BitASCII(string memory s) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(7, div(not(0), 255))
            result := 1
            let n := mload(s)
            if n {
                let o := add(s, 0x20)
                let end := add(o, n)
                let last := mload(end)
                mstore(end, 0)
                for {} 1 {} {
                    if and(mask, mload(o)) {
                        result := 0
                        break
                    }
                    o := add(o, 0x20)
                    if iszero(lt(o, end)) { break }
                }
                mstore(end, last)
            }
        }
    }

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

    // For performance and bytecode compactness, all indices of the following operations
    // are byte (ASCII) offsets, not UTF character offsets.

    /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.
    function replace(string memory subject, string memory search, string memory replacement)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)
            let replacementLength := mload(replacement)

            subject := add(subject, 0x20)
            search := add(search, 0x20)
            replacement := add(replacement, 0x20)
            result := add(mload(0x40), 0x20)

            let subjectEnd := add(subject, subjectLength)
            if iszero(gt(searchLength, subjectLength)) {
                let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(search)
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                mstore(result, t)
                                result := add(result, 1)
                                subject := add(subject, 1)
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        for { let o := 0 } 1 {} {
                            mstore(add(result, o), mload(add(replacement, o)))
                            o := add(o, 0x20)
                            if iszero(lt(o, replacementLength)) { break }
                        }
                        result := add(result, replacementLength)
                        subject := add(subject, searchLength)
                        if searchLength {
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(result, t)
                    result := add(result, 1)
                    subject := add(subject, 1)
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
            }

            let resultRemainder := result
            result := add(mload(0x40), 0x20)
            let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
            // Copy the rest of the string one word at a time.
            for {} lt(subject, subjectEnd) {} {
                mstore(resultRemainder, mload(subject))
                resultRemainder := add(resultRemainder, 0x20)
                subject := add(subject, 0x20)
            }
            result := sub(result, 0x20)
            let last := add(add(result, 0x20), k) // Zeroize the slot after the string.
            mstore(last, 0)
            mstore(0x40, add(last, 0x20)) // Allocate the memory.
            mstore(result, k) // Store the length.
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let subjectLength := mload(subject) } 1 {} {
                if iszero(mload(search)) {
                    if iszero(gt(from, subjectLength)) {
                        result := from
                        break
                    }
                    result := subjectLength
                    break
                }
                let searchLength := mload(search)
                let subjectStart := add(subject, 0x20)

                result := not(0) // Initialize to `NOT_FOUND`.

                subject := add(subjectStart, from)
                let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)

                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(add(search, 0x20))

                if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }

                if iszero(lt(searchLength, 0x20)) {
                    for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, searchLength), h) {
                                result := sub(subject, subjectStart)
                                break
                            }
                        }
                        subject := add(subject, 1)
                        if iszero(lt(subject, end)) { break }
                    }
                    break
                }
                for {} 1 {} {
                    if iszero(shr(m, xor(mload(subject), s))) {
                        result := sub(subject, subjectStart)
                        break
                    }
                    subject := add(subject, 1)
                    if iszero(lt(subject, end)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256 result)
    {
        result = indexOf(subject, search, 0);
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                result := not(0) // Initialize to `NOT_FOUND`.
                let searchLength := mload(search)
                if gt(searchLength, mload(subject)) { break }
                let w := result

                let fromMax := sub(mload(subject), searchLength)
                if iszero(gt(fromMax, from)) { from := fromMax }

                let end := add(add(subject, 0x20), w)
                subject := add(add(subject, 0x20), from)
                if iszero(gt(subject, end)) { break }
                // As this function is not too often used,
                // we shall simply use keccak256 for smaller bytecode size.
                for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                    if eq(keccak256(subject, searchLength), h) {
                        result := sub(subject, add(end, 1))
                        break
                    }
                    subject := add(subject, w) // `sub(subject, 1)`.
                    if iszero(gt(subject, end)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256 result)
    {
        result = lastIndexOf(subject, search, uint256(int256(-1)));
    }

    /// @dev Returns whether `subject` starts with `search`.
    function startsWith(string memory subject, string memory search)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLength := mload(search)
            // Just using keccak256 directly is actually cheaper.
            // forgefmt: disable-next-item
            result := and(
                iszero(gt(searchLength, mload(subject))),
                eq(
                    keccak256(add(subject, 0x20), searchLength),
                    keccak256(add(search, 0x20), searchLength)
                )
            )
        }
    }

    /// @dev Returns whether `subject` ends with `search`.
    function endsWith(string memory subject, string memory search)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLength := mload(search)
            let subjectLength := mload(subject)
            // Whether `search` is not longer than `subject`.
            let withinRange := iszero(gt(searchLength, subjectLength))
            // Just using keccak256 directly is actually cheaper.
            // forgefmt: disable-next-item
            result := and(
                withinRange,
                eq(
                    keccak256(
                        // `subject + 0x20 + max(subjectLength - searchLength, 0)`.
                        add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
                        searchLength
                    ),
                    keccak256(add(search, 0x20), searchLength)
                )
            )
        }
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(string memory subject, uint256 times)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(or(iszero(times), iszero(subjectLength))) {
                subject := add(subject, 0x20)
                result := mload(0x40)
                let output := add(result, 0x20)
                for {} 1 {} {
                    // Copy the `subject` one word at a time.
                    for { let o := 0 } 1 {} {
                        mstore(add(output, o), mload(add(subject, o)))
                        o := add(o, 0x20)
                        if iszero(lt(o, subjectLength)) { break }
                    }
                    output := add(output, subjectLength)
                    times := sub(times, 1)
                    if iszero(times) { break }
                }
                mstore(output, 0) // Zeroize the slot after the string.
                let resultLength := sub(output, add(result, 0x20))
                mstore(result, resultLength) // Store the length.
                // Allocate the memory.
                mstore(0x40, add(result, add(resultLength, 0x20)))
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function slice(string memory subject, uint256 start, uint256 end)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(gt(subjectLength, end)) { end := subjectLength }
            if iszero(gt(subjectLength, start)) { start := subjectLength }
            if lt(start, end) {
                result := mload(0x40)
                let resultLength := sub(end, start)
                mstore(result, resultLength)
                subject := add(subject, start)
                let w := not(0x1f)
                // Copy the `subject` one word at a time, backwards.
                for { let o := and(add(resultLength, 0x1f), w) } 1 {} {
                    mstore(add(result, o), mload(add(subject, o)))
                    o := add(o, w) // `sub(o, 0x20)`.
                    if iszero(o) { break }
                }
                // Zeroize the slot after the string.
                mstore(add(add(result, 0x20), resultLength), 0)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
    /// `start` is a byte offset.
    function slice(string memory subject, uint256 start)
        internal
        pure
        returns (string memory result)
    {
        result = slice(subject, start, uint256(int256(-1)));
    }

    /// @dev Returns all the indices of `search` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256[] memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)

            if iszero(gt(searchLength, subjectLength)) {
                subject := add(subject, 0x20)
                search := add(search, 0x20)
                result := add(mload(0x40), 0x20)

                let subjectStart := subject
                let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(search)
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                subject := add(subject, 1)
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Append to `result`.
                        mstore(result, sub(subject, subjectStart))
                        result := add(result, 0x20)
                        // Advance `subject` by `searchLength`.
                        subject := add(subject, searchLength)
                        if searchLength {
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    subject := add(subject, 1)
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
                let resultEnd := result
                // Assign `result` to the free memory pointer.
                result := mload(0x40)
                // Store the length of `result`.
                mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(resultEnd, 0x20))
            }
        }
    }

    /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
    function split(string memory subject, string memory delimiter)
        internal
        pure
        returns (string[] memory result)
    {
        uint256[] memory indices = indicesOf(subject, delimiter);
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(0x1f)
            let indexPtr := add(indices, 0x20)
            let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
            mstore(add(indicesEnd, w), mload(subject))
            mstore(indices, add(mload(indices), 1))
            let prevIndex := 0
            for {} 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let elementLength := sub(index, prevIndex)
                    mstore(element, elementLength)
                    // Copy the `subject` one word at a time, backwards.
                    for { let o := and(add(elementLength, 0x1f), w) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := add(o, w) // `sub(o, 0x20)`.
                        if iszero(o) { break }
                    }
                    // Zeroize the slot after the string.
                    mstore(add(add(element, 0x20), elementLength), 0)
                    // Allocate memory for the length and the bytes,
                    // rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))
                    // Store the `element` into the array.
                    mstore(indexPtr, element)
                }
                prevIndex := add(index, mload(delimiter))
                indexPtr := add(indexPtr, 0x20)
                if iszero(lt(indexPtr, indicesEnd)) { break }
            }
            result := indices
            if iszero(mload(delimiter)) {
                result := add(indices, 0x20)
                mstore(result, sub(mload(indices), 2))
            }
        }
    }

    /// @dev Returns a concatenated string of `a` and `b`.
    /// Cheaper than `string.concat()` and does not de-align the free memory pointer.
    function concat(string memory a, string memory b)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(0x1f)
            result := mload(0x40)
            let aLength := mload(a)
            // Copy `a` one word at a time, backwards.
            for { let o := and(add(mload(a), 0x20), w) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let bLength := mload(b)
            let output := add(result, mload(a))
            // Copy `b` one word at a time, backwards.
            for { let o := and(add(bLength, 0x20), w) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let totalLength := add(aLength, bLength)
            let last := add(add(result, 0x20), totalLength)
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Stores the length.
            mstore(result, totalLength)
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 0x1f), w))
        }
    }

    /// @dev Returns a copy of the string in either lowercase or UPPERCASE.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function toCase(string memory subject, bool toUpper)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let length := mload(subject)
            if length {
                result := add(mload(0x40), 0x20)
                subject := add(subject, 1)
                let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
                let w := not(0)
                for { let o := length } 1 {} {
                    o := add(o, w)
                    let b := and(0xff, mload(add(subject, o)))
                    mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
                    if iszero(o) { break }
                }
                result := mload(0x40)
                mstore(result, length) // Store the length.
                let last := add(add(result, 0x20), length)
                mstore(last, 0) // Zeroize the slot after the string.
                mstore(0x40, add(last, 0x20)) // Allocate the memory.
            }
        }
    }

    /// @dev Returns a lowercased copy of the string.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function lower(string memory subject) internal pure returns (string memory result) {
        result = toCase(subject, false);
    }

    /// @dev Returns an UPPERCASED copy of the string.
    /// WARNING! This function is only compatible with 7-bit ASCII strings.
    function upper(string memory subject) internal pure returns (string memory result) {
        result = toCase(subject, true);
    }

    /// @dev Escapes the string to be used within HTML tags.
    function escapeHTML(string memory s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {
                let end := add(s, mload(s))
                result := add(mload(0x40), 0x20)
                // Store the bytes of the packed offsets and strides into the scratch space.
                // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
                mstore(0x1f, 0x900094)
                mstore(0x08, 0xc0000000a6ab)
                // Store "&quot;&amp;&#39;&lt;&gt;" into the scratch space.
                mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
            } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                // Not in `["\"","'","&","<",">"]`.
                if iszero(and(shl(c, 1), 0x500000c400000000)) {
                    mstore8(result, c)
                    result := add(result, 1)
                    continue
                }
                let t := shr(248, mload(c))
                mstore(result, mload(and(t, 0x1f)))
                result := add(result, shr(5, t))
            }
            let last := result
            mstore(last, 0) // Zeroize the slot after the string.
            result := mload(0x40)
            mstore(result, sub(last, add(result, 0x20))) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate the memory.
        }
    }

    /// @dev Escapes the string to be used within double-quotes in a JSON.
    function escapeJSON(string memory s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {
                let end := add(s, mload(s))
                result := add(mload(0x40), 0x20)
                // Store "\\u0000" in scratch space.
                // Store "0123456789abcdef" in scratch space.
                // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
                // into the scratch space.
                mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
                // Bitmask for detecting `["\"","\\"]`.
                let e := or(shl(0x22, 1), shl(0x5c, 1))
            } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                if iszero(lt(c, 0x20)) {
                    if iszero(and(shl(c, 1), e)) {
                        // Not in `["\"","\\"]`.
                        mstore8(result, c)
                        result := add(result, 1)
                        continue
                    }
                    mstore8(result, 0x5c) // "\\".
                    mstore8(add(result, 1), c)
                    result := add(result, 2)
                    continue
                }
                if iszero(and(shl(c, 1), 0x3700)) {
                    // Not in `["\b","\t","\n","\f","\d"]`.
                    mstore8(0x1d, mload(shr(4, c))) // Hex value.
                    mstore8(0x1e, mload(and(c, 15))) // Hex value.
                    mstore(result, mload(0x19)) // "\\u00XX".
                    result := add(result, 6)
                    continue
                }
                mstore8(result, 0x5c) // "\\".
                mstore8(add(result, 1), mload(add(c, 8)))
                result := add(result, 2)
            }
            let last := result
            mstore(last, 0) // Zeroize the slot after the string.
            result := mload(0x40)
            mstore(result, sub(last, add(result, 0x20))) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate the memory.
        }
    }

    /// @dev Returns whether `a` equals `b`.
    function eq(string memory a, string memory b) internal pure returns (bool result) {
        assembly {
            result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
        }
    }

    /// @dev Packs a single string with its length into a single word.
    /// Returns `bytes32(0)` if the length is zero or greater than 31.
    function packOne(string memory a) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // We don't need to zero right pad the string,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    // Load the length and the bytes.
                    mload(add(a, 0x1f)),
                    // `length != 0 && length < 32`. Abuses underflow.
                    // Assumes that the length is valid and within the block gas limit.
                    lt(sub(mload(a), 1), 0x1f)
                )
        }
    }

    /// @dev Unpacks a string packed using {packOne}.
    /// Returns the empty string if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packOne}, the output behaviour is undefined.
    function unpackOne(bytes32 packed) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the free memory pointer.
            result := mload(0x40)
            // Allocate 2 words (1 for the length, 1 for the bytes).
            mstore(0x40, add(result, 0x40))
            // Zeroize the length slot.
            mstore(result, 0)
            // Store the length and bytes.
            mstore(add(result, 0x1f), packed)
            // Right pad with zeroes.
            mstore(add(add(result, 0x20), mload(result)), 0)
        }
    }

    /// @dev Packs two strings with their lengths into a single word.
    /// Returns `bytes32(0)` if combined length is zero or greater than 30.
    function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let aLength := mload(a)
            // We don't need to zero right pad the strings,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    // Load the length and the bytes of `a` and `b`.
                    or(
                        shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
                        mload(sub(add(b, 0x1e), aLength))
                    ),
                    // `totalLength != 0 && totalLength < 31`. Abuses underflow.
                    // Assumes that the lengths are valid and within the block gas limit.
                    lt(sub(add(aLength, mload(b)), 1), 0x1e)
                )
        }
    }

    /// @dev Unpacks strings packed using {packTwo}.
    /// Returns the empty strings if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packTwo}, the output behaviour is undefined.
    function unpackTwo(bytes32 packed)
        internal
        pure
        returns (string memory resultA, string memory resultB)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the free memory pointer.
            resultA := mload(0x40)
            resultB := add(resultA, 0x40)
            // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
            mstore(0x40, add(resultB, 0x40))
            // Zeroize the length slots.
            mstore(resultA, 0)
            mstore(resultB, 0)
            // Store the lengths and bytes.
            mstore(add(resultA, 0x1f), packed)
            mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
            // Right pad with zeroes.
            mstore(add(add(resultA, 0x20), mload(resultA)), 0)
            mstore(add(add(resultB, 0x20), mload(resultB)), 0)
        }
    }

    /// @dev Directly returns `a` without copying.
    function directReturn(string memory a) internal pure {
        assembly {
            // Assumes that the string does not start from the scratch space.
            let retStart := sub(a, 0x20)
            let retSize := add(mload(a), 0x40)
            // Right pad with zeroes. Just in case the string is produced
            // by a method that doesn't zero right pad.
            mstore(add(retStart, retSize), 0)
            // Store the return offset.
            mstore(retStart, 0x20)
            // End the transaction, returning the string.
            return(retStart, retSize)
        }
    }
}

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

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

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

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

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

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

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

                    // Write 4 bytes. Optimized for fewer stack operations.
                    mstore8(0, mload(and(shr(18, input), 0x3F)))
                    mstore8(1, mload(and(shr(12, input), 0x3F)))
                    mstore8(2, mload(and(shr(6, input), 0x3F)))
                    mstore8(3, mload(and(input, 0x3F)))
                    mstore(ptr, mload(0x00))

                    ptr := add(ptr, 4) // Advance 4 bytes.
                    if iszero(lt(ptr, end)) { break }
                }
                mstore(0x40, add(end, 0x20)) // Allocate the memory.
                // Equivalent to `o = [0, 2, 1][dataLength % 3]`.
                let o := div(2, mod(dataLength, 3))
                // Offset `ptr` and pad with '='. We can simply write over the end.
                mstore(sub(ptr, o), shl(240, 0x3d3d))
                // Set `o` to zero if there is padding.
                o := mul(iszero(iszero(noPadding)), o)
                mstore(sub(ptr, o), 0) // Zeroize the slot after the string.
                mstore(result, sub(encodedLength, o)) // Store the length.
            }
        }
    }

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

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

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

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

                for {} 1 {} {
                    // If padded.
                    if iszero(and(dataLength, 3)) {
                        let t := xor(mload(add(data, dataLength)), 0x3d3d)
                        // forgefmt: disable-next-item
                        decodedLength := sub(
                            decodedLength,
                            add(iszero(byte(30, t)), iszero(byte(31, t)))
                        )
                        break
                    }
                    // If non-padded.
                    decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))
                    break
                }
                result := mload(0x40)

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

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

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

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

                    // Write 3 bytes.
                    // forgefmt: disable-next-item
                    mstore(ptr, or(
                        and(m, mload(byte(28, input))),
                        shr(6, or(
                            and(m, mload(byte(29, input))),
                            shr(6, or(
                                and(m, mload(byte(30, input))),
                                shr(6, mload(byte(31, input)))
                            ))
                        ))
                    ))
                    ptr := add(ptr, 3)
                    if iszero(lt(ptr, end)) { break }
                }
                mstore(0x40, add(end, 0x20)) // Allocate the memory.
                mstore(end, 0) // Zeroize the slot after the bytes.
                mstore(0x60, 0) // Restore the zero slot.
            }
        }
    }
}

File 9 of 16 : XXYYZZMint.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {XXYYZZCore} from "./XXYYZZCore.sol";

/**
 * @title XXYYZZMint
 * @author emo.eth
 * @notice This contract handles minting of XXYYZZ tokens.
 *         Tokens may be minted with a pseudorandom hex value, or with a specific hex value.
 *         The "Specific" methods allow for minting tokens with specific hex values with a commit-reveal scheme.
 *         Users may protect themselves against front-running by
 */
abstract contract XXYYZZMint is XXYYZZCore {
    uint256 public immutable MAX_MINT_CLOSE_TIMESTAMP;

    constructor(address initialOwner, uint256 maxBatchSize) XXYYZZCore(initialOwner, maxBatchSize) {
        MAX_MINT_CLOSE_TIMESTAMP = block.timestamp + 14 days;
    }

    //////////
    // MINT //
    //////////

    /**
     * @notice Mint a token with a pseudorandom hex value.
     * @return The token ID
     */
    function mint() public payable returns (uint256) {
        uint256 newAmount = _checkMintAndIncrementNumMinted(1);
        // get pseudorandom hex id – doesn't need to be derived from caller
        uint256 tokenId = _findAvailableHex(newAmount);
        _mint(msg.sender, tokenId);
        return tokenId;
    }

    /**
     * @notice Mint a number of tokens with pseudorandom hex values.
     * @param quantity The number of tokens to mint
     * @return The token IDs
     */
    function mint(uint256 quantity) public payable returns (uint256[] memory) {
        return _checkMintTo(msg.sender, quantity);
    }

    function mintTo(address to, uint256 quantity) public payable returns (uint256[] memory) {
        return _checkMintTo(to, quantity);
    }

    /**
     * @notice Mint a token with a specific hex value.
     *         A user must first call commit(bytes32) or batchCommit(bytes32[]) with the result(s) of
     *         computeCommittment(address,uint256,bytes32), and wait at least one minute.
     *         When calling mintSpecific, the "salt" should be the bytes32 salt provided to `computeCommitment` when
     *         creating the commitment hash.
     *
     *         Example: To register 0x123456 with salt bytes32(0xDEADBEEF)
     *             1. Call `computeCommitment(<minting addr>, 0x123456, bytes32(0xDEADBEEF))` for `bytes32 result`
     *             2. Call `commit(result)`
     *             3. Wait at least 1 minute, but less than 1 day
     *             4. Call `mintSpecific(0x123456, bytes32(0xDEADBEEF))`
     * @param id The 6-hex-digit token ID to mint
     * @param salt The salt used in the commitment for the commitment
     */
    function mintSpecific(uint256 id, bytes32 salt) public payable {
        _checkMintAndIncrementNumMinted(1);
        _mintSpecific(id, salt);
    }

    /**
     * @notice Mint a number of tokens with specific hex values.
     *         A user must first call commit(bytes32) with the result of
     *         `computeBatchCommitment(address,uint256[],bytes32)`, and wait at least COMMITMENT_LIFESPAN seconds.
     * @param ids The 6-hex-digit token IDs to mint
     * @param salt The salt used in the batch commitment
     * @return An array of booleans indicating whether each token was minted
     */
    function batchMintSpecific(uint256[] calldata ids, bytes32 salt) public payable returns (bool[] memory) {
        _validateBatchMintAndTimestamp(ids);
        bytes32 computedCommitment = computeBatchCommitment(msg.sender, ids, salt);
        _assertCommittedReveal(computedCommitment);
        return _batchMintAndIncrementAndRefund(ids);
    }

    /////////////
    // HELPERS //
    /////////////

    /**
     * @dev Mint tokens, validate that tokens were minted, and increment the number of minted tokens
     * @param to Recipient of the tokens
     * @param quantity Number of tokens to mint
     */
    function _checkMintTo(address to, uint256 quantity) internal returns (uint256[] memory) {
        // check payment and quantity once
        uint256 newAmount = _checkMintAndIncrementNumMinted(quantity);
        return _mintTo(to, quantity, newAmount);
    }

    /**
     * @dev Mint tokens, validate that tokens were minted, and increment the number of minted tokens
     * @param to Recipient of the tokens
     * @param quantity Number of tokens to mint
     */
    function _mintTo(address to, uint256 quantity, uint256 newAmount) internal returns (uint256[] memory) {
        uint256[] memory tokenIds = new uint256[](quantity);
        for (uint256 i; i < quantity;) {
            // get pseudorandom hex id
            uint256 tokenId = _findAvailableHex(newAmount);
            _mint(to, tokenId);
            tokenIds[i] = tokenId;
            unchecked {
                ++i;
                ++newAmount;
            }
        }
        return tokenIds;
    }

    /**
     * @dev Mint tokens, validate that tokens were minted, increment the number of minted tokens, and refund any
     *      overpayment
     * @param ids The 6-hex-digit token IDs to mint
     */
    function _batchMintAndIncrementAndRefund(uint256[] calldata ids) internal returns (bool[] memory) {
        bool[] memory minted = new bool[](ids.length);
        uint256 quantityMinted;
        for (uint256 i; i < ids.length;) {
            if (_mintSpecificUnprotected(ids[i])) {
                minted[i] = true;
                unchecked {
                    ++quantityMinted;
                }
            }
            unchecked {
                ++i;
            }
        }
        if (quantityMinted == 0) {
            revert NoneAvailable();
        }

        _incrementNumMintedAndRefundOverpayment(quantityMinted);
        return minted;
    }

    /**
     * @dev Check payment and quantity validation – quantityRequested for payment, quantityAvailable for updating
     *      the number of minted tokens, which may be different
     * @param quantityRequested The number of tokens requested by the user, which must be paid for
     * @return The new number of minted tokens
     */
    function _checkMintAndIncrementNumMinted(uint256 quantityRequested) internal returns (uint256) {
        if (block.timestamp > MAX_MINT_CLOSE_TIMESTAMP) {
            revert MintClosed();
        }
        _validatePayment(MINT_PRICE, quantityRequested);

        // increment supply before minting
        uint128 newAmount;
        // this can be unchecked because an ID can only be minted once, and all IDs are later validated to be uint24s
        unchecked {
            newAmount = _numMinted + uint128(quantityRequested);
        }
        _numMinted = newAmount;
        return newAmount;
    }

    /**
     * @dev Increment the number of minted tokens and refund any overpayment
     * @param quantity The number of tokens actually minted
     */
    function _incrementNumMintedAndRefundOverpayment(uint256 quantity) internal returns (uint256) {
        uint256 newAmount;
        // this can be unchecked because an ID can only be minted once, and all IDs are validated to be uint24s
        // overflow here implies invalid IDs down the line, which will cause a revert when minting
        unchecked {
            newAmount = _numMinted + quantity;
        }
        _numMinted = uint32(newAmount);
        _refundOverpayment(MINT_PRICE, quantity);
        return newAmount;
    }

    /**
     * @dev Validate the timestamp and payment for a batch mint
     * @param ids The 6-hex-digit token IDs to mint
     */
    function _validateBatchMintAndTimestamp(uint256[] calldata ids) internal view {
        if (block.timestamp > MAX_MINT_CLOSE_TIMESTAMP) {
            revert MintClosed();
        }
        if (ids.length > MAX_SPECIFIC_BATCH_SIZE) {
            revert MaxBatchSizeExceeded();
        }
        _validatePayment(ids.length, MINT_PRICE);
    }
}

File 10 of 16 : SeaDropSpecific.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

struct PublicDrop {
    uint80 mintPrice; // 80/256 bits
    uint48 startTime; // 128/256 bits
    uint48 endTime; // 176/256 bits
    uint16 maxTotalMintableByWallet; // 224/256 bits
    uint16 feeBps; // 240/256 bits
    bool restrictFeeRecipients; // 248/256 bits
}

interface ISeaDrop {
    /**
     * @notice Updates the public drop data for the nft contract
     *         and emits an event.
     *
     *         This method assume msg.sender is an nft contract and its
     *         ERC165 interface id matches INonFungibleSeaDropToken.
     *
     *         Note: Be sure only authorized users can call this from
     *         token contracts that implement INonFungibleSeaDropToken.
     *
     * @param publicDrop The public drop data.
     */
    function updatePublicDrop(PublicDrop calldata publicDrop) external;

    /**
     * @notice Updates the creator payout address and emits an event.
     *
     *         This method assume msg.sender is an nft contract and its
     *         ERC165 interface id matches INonFungibleSeaDropToken.
     *
     *         Note: Be sure only authorized users can call this from
     *         token contracts that implement INonFungibleSeaDropToken.
     *
     * @param payoutAddress The creator payout address.
     */
    function updateCreatorPayoutAddress(address payoutAddress) external;

    /**
     * @notice Updates the allowed fee recipient and emits an event.
     *
     *         This method assume msg.sender is an nft contract and its
     *         ERC165 interface id matches INonFungibleSeaDropToken.
     *
     *         Note: Be sure only authorized users can call this from
     *         token contracts that implement INonFungibleSeaDropToken.
     *
     * @param feeRecipient The fee recipient.
     * @param allowed      If the fee recipient is allowed.
     */
    function updateAllowedFeeRecipient(address feeRecipient, bool allowed) external;

    /**
     * @notice Updates the allowed payer and emits an event.
     *
     *         This method assume msg.sender is an nft contract and its
     *         ERC165 interface id matches INonFungibleSeaDropToken.
     *
     *         Note: Be sure only authorized users can call this from
     *         token contracts that implement INonFungibleSeaDropToken.
     *
     * @param payer   The payer to add or remove.
     * @param allowed Whether to add or remove the payer.
     */
    function updatePayer(address payer, bool allowed) external;
}

File 11 of 16 : ERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple ERC721 implementation with storage hitchhiking.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol)
/// Note:
/// The ERC721 standard allows for self-approvals.
/// For performance, this implementation WILL NOT revert for such actions.
/// Please add any checks with overrides if desired.
abstract contract ERC721 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev An account can hold up to 4294967295 tokens.
    uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Only the token owner or an approved account can manage the token.
    error NotOwnerNorApproved();

    /// @dev The token does not exist.
    error TokenDoesNotExist();

    /// @dev The token already exists.
    error TokenAlreadyExists();

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

    /// @dev Cannot mint or transfer to the zero address.
    error TransferToZeroAddress();

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

    /// @dev The recipient's balance has overflowed.
    error AccountBalanceOverflow();

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

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

    /// @dev Emitted when token `id` is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 indexed id);

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

    /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
    event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 private constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
    uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
        0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;

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

    /// @dev The ownership data slot of `id` is given by:
    /// ```
    ///     mstore(0x00, id)
    ///     mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
    ///     let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
    /// ```
    /// Bits Layout:
    // - [0..159]   `addr`
    // - [160..223] `extraData`
    ///
    /// The approved address slot is given by: `add(1, ownershipSlot)`.
    ///
    /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip
    ///
    /// The balance slot of `owner` is given by:
    /// ```
    ///     mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let balanceSlot := keccak256(0x0c, 0x1c)
    /// ```
    /// Bits Layout:
    /// - [0..31]   `balance`
    /// - [32..225] `aux`
    ///
    /// The `operator` approval slot of `owner` is given by:
    /// ```
    ///     mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
    ///     mstore(0x00, owner)
    ///     let operatorApprovalSlot := keccak256(0x0c, 0x30)
    /// ```
    uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192;

    /// @dev Pre-shifted and pre-masked constant.
    uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC721 METADATA                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the token collection name.
    function name() public view virtual returns (string memory);

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

    /// @dev Returns the Uniform Resource Identifier (URI) for token `id`.
    function tokenURI(uint256 id) public view virtual returns (string memory);

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

    /// @dev Returns the owner of token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function ownerOf(uint256 id) public view virtual returns (address result) {
        result = _ownerOf(id);
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(result) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns the number of tokens owned by `owner`.
    ///
    /// Requirements:
    /// - `owner` must not be the zero address.
    function balanceOf(address owner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Revert if the `owner` is the zero address.
            if iszero(owner) {
                mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`.
                revert(0x1c, 0x04)
            }
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE)
        }
    }

    /// @dev Returns the account approved to managed token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function getApproved(uint256 id) public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            if iszero(shr(96, shl(96, sload(ownershipSlot)))) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            result := sload(add(1, ownershipSlot))
        }
    }

    /// @dev Sets `account` as the approved account to manage token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - The caller must be the owner of the token,
    ///   or an approved operator for the token owner.
    ///
    /// Emits a {Approval} event.
    function approve(address account, uint256 id) public payable virtual {
        _approve(msg.sender, account, id);
    }

    /// @dev Returns whether `operator` is approved to manage the tokens of `owner`.
    function isApprovedForAll(address owner, address operator)
        public
        view
        virtual
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, operator)
            mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x30))
        }
    }

    /// @dev Sets whether `operator` is approved to manage the tokens of the caller.
    ///
    /// Emits a {ApprovalForAll} event.
    function setApprovalForAll(address operator, bool isApproved) public virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Convert to 0 or 1.
            isApproved := iszero(iszero(isApproved))
            // Update the `isApproved` for (`msg.sender`, `operator`).
            mstore(0x1c, operator)
            mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x30), isApproved)
            // Emit the {ApprovalForAll} event.
            mstore(0x00, isApproved)
            log3(
                0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))
            )
        }
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 id) public payable virtual {
        _beforeTokenTransfer(from, to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            from := and(bitmaskAddress, from)
            to := and(bitmaskAddress, to)
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller()))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            let owner := and(bitmaskAddress, ownershipPacked)
            // Revert if `from` is not the owner, or does not exist.
            if iszero(mul(owner, eq(owner, from))) {
                if iszero(owner) {
                    mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                    revert(0x1c, 0x04)
                }
                mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`.
                revert(0x1c, 0x04)
            }
            // Revert if `to` is the zero address.
            if iszero(to) {
                mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                revert(0x1c, 0x04)
            }
            // Load, check, and update the token approval.
            {
                mstore(0x00, from)
                let approvedAddress := sload(add(1, ownershipSlot))
                // Revert if the caller is not the owner, nor approved.
                if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Update with the new owner.
            sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
            // Decrement the balance of `from`.
            {
                let fromBalanceSlot := keccak256(0x0c, 0x1c)
                sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
            }
            // Increment the balance of `to`.
            {
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x1c)
                let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
                if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) {
                    mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                    revert(0x1c, 0x04)
                }
                sstore(toBalanceSlot, toBalanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
        }
        _afterTokenTransfer(from, to, id);
    }

    /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`.
    function safeTransferFrom(address from, address to, uint256 id) public payable virtual {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - 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 id, bytes calldata data)
        public
        payable
        virtual
    {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
    /// See: https://eips.ethereum.org/EIPS/eip-165
    /// This function call must use less than 30000 gas.
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f.
            result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
        }
    }

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

    /// @dev Returns if token `id` exists.
    function _exists(uint256 id) internal view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Returns the owner of token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _ownerOf(uint256 id) internal view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))
        }
    }

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

    /// @dev Returns the auxiliary data for `owner`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _getAux(address owner) internal view virtual returns (uint224 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            result := shr(32, sload(keccak256(0x0c, 0x1c)))
        }
    }

    /// @dev Set the auxiliary data for `owner` to `value`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _setAux(address owner, uint224 value) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            let balanceSlot := keccak256(0x0c, 0x1c)
            let packed := sload(balanceSlot)
            sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed)))))
        }
    }

    /// @dev Returns the extra data for token `id`.
    /// Minting, transferring, burning a token will not change the extra data.
    /// The extra data can be set on a non existent token.
    function _getExtraData(uint256 id) internal view virtual returns (uint96 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Sets the extra data for token `id` to `value`.
    /// Minting, transferring, burning a token will not change the extra data.
    /// The extra data can be set on a non existent token.
    function _setExtraData(uint256 id, uint96 value) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let packed := sload(ownershipSlot)
            sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed)))))
        }
    }

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

    /// @dev Mints token `id` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must not exist.
    /// - `to` cannot be the zero address.
    ///
    /// Emits a {Transfer} event.
    function _mint(address to, uint256 id) internal virtual {
        _beforeTokenTransfer(address(0), to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            to := shr(96, shl(96, to))
            // Revert if `to` is the zero address.
            if iszero(to) {
                mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                revert(0x1c, 0x04)
            }
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            // Revert if the token already exists.
            if shl(96, ownershipPacked) {
                mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`.
                revert(0x1c, 0x04)
            }
            // Update with the owner.
            sstore(ownershipSlot, or(ownershipPacked, to))
            // Increment the balance of the owner.
            {
                mstore(0x00, to)
                let balanceSlot := keccak256(0x0c, 0x1c)
                let balanceSlotPacked := add(sload(balanceSlot), 1)
                if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) {
                    mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                    revert(0x1c, 0x04)
                }
                sstore(balanceSlot, balanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
        }
        _afterTokenTransfer(address(0), to, id);
    }

    /// @dev Equivalent to `_safeMint(to, id, "")`.
    function _safeMint(address to, uint256 id) internal virtual {
        _safeMint(to, id, "");
    }

    /// @dev Mints token `id` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must not exist.
    /// - `to` cannot be the zero address.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function _safeMint(address to, uint256 id, bytes memory data) internal virtual {
        _mint(to, id);
        if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data);
    }

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

    /// @dev Equivalent to `_burn(address(0), id)`.
    function _burn(uint256 id) internal virtual {
        _burn(address(0), id);
    }

    /// @dev Destroys token `id`, using `by`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _burn(address by, uint256 id) internal virtual {
        address owner = ownerOf(id);
        _beforeTokenTransfer(owner, address(0), id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            by := shr(96, shl(96, by))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            // Reload the owner in case it is changed in `_beforeTokenTransfer`.
            owner := shr(96, shl(96, ownershipPacked))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // Load and check the token approval.
            {
                mstore(0x00, owner)
                let approvedAddress := sload(add(1, ownershipSlot))
                // If `by` is not the zero address, do the authorization check.
                // Revert if the `by` is not the owner, nor approved.
                if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Clear the owner.
            sstore(ownershipSlot, xor(ownershipPacked, owner))
            // Decrement the balance of `owner`.
            {
                let balanceSlot := keccak256(0x0c, 0x1c)
                sstore(balanceSlot, sub(sload(balanceSlot), 1))
            }
            // Emit the {Transfer} event.
            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id)
        }
        _afterTokenTransfer(owner, address(0), id);
    }

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

    /// @dev Returns whether `account` is the owner of token `id`, or is approved to managed it.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function _isApprovedOrOwner(address account, uint256 id)
        internal
        view
        virtual
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            // Clear the upper 96 bits.
            account := shr(96, shl(96, account))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let owner := shr(96, shl(96, sload(ownershipSlot)))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // Check if `account` is the `owner`.
            if iszero(eq(account, owner)) {
                mstore(0x00, owner)
                // Check if `account` is approved to
                if iszero(sload(keccak256(0x0c, 0x30))) {
                    result := eq(account, sload(add(1, ownershipSlot)))
                }
            }
        }
    }

    /// @dev Returns the account approved to manage token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _getApproved(uint256 id) internal view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Equivalent to `_approve(address(0), account, id)`.
    function _approve(address account, uint256 id) internal virtual {
        _approve(address(0), account, id);
    }

    /// @dev Sets `account` as the approved account to manage token `id`, using `by`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - If `by` is not the zero address, `by` must be the owner
    ///   or an approved operator for the token owner.
    ///
    /// Emits a {Transfer} event.
    function _approve(address by, address account, uint256 id) internal virtual {
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            account := and(bitmaskAddress, account)
            by := and(bitmaskAddress, by)
            // Load the owner of the token.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let owner := and(bitmaskAddress, sload(ownershipSlot))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // If `by` is not the zero address, do the authorization check.
            // Revert if `by` is not the owner, nor approved.
            if iszero(or(iszero(by), eq(by, owner))) {
                mstore(0x00, owner)
                if iszero(sload(keccak256(0x0c, 0x30))) {
                    mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                    revert(0x1c, 0x04)
                }
            }
            // Sets `account` as the approved account to manage `id`.
            sstore(add(1, ownershipSlot), account)
            // Emit the {Approval} event.
            log4(0x00, 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id)
        }
    }

    /// @dev Approve or remove the `operator` as an operator for `by`,
    /// without authorization checks.
    ///
    /// Emits a {ApprovalForAll} event.
    function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            by := shr(96, shl(96, by))
            operator := shr(96, shl(96, operator))
            // Convert to 0 or 1.
            isApproved := iszero(iszero(isApproved))
            // Update the `isApproved` for (`by`, `operator`).
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
            mstore(0x00, by)
            sstore(keccak256(0x0c, 0x30), isApproved)
            // Emit the {ApprovalForAll} event.
            mstore(0x00, isApproved)
            log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator)
        }
    }

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

    /// @dev Equivalent to `_transfer(address(0), from, to, id)`.
    function _transfer(address from, address to, uint256 id) internal virtual {
        _transfer(address(0), from, to, id);
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _transfer(address by, address from, address to, uint256 id) internal virtual {
        _beforeTokenTransfer(from, to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            from := and(bitmaskAddress, from)
            to := and(bitmaskAddress, to)
            by := and(bitmaskAddress, by)
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            let owner := and(bitmaskAddress, ownershipPacked)
            // Revert if `from` is not the owner, or does not exist.
            if iszero(mul(owner, eq(owner, from))) {
                if iszero(owner) {
                    mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                    revert(0x1c, 0x04)
                }
                mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`.
                revert(0x1c, 0x04)
            }
            // Revert if `to` is the zero address.
            if iszero(to) {
                mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
                revert(0x1c, 0x04)
            }
            // Load, check, and update the token approval.
            {
                mstore(0x00, from)
                let approvedAddress := sload(add(1, ownershipSlot))
                // If `by` is not the zero address, do the authorization check.
                // Revert if the `by` is not the owner, nor approved.
                if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Update with the new owner.
            sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
            // Decrement the balance of `from`.
            {
                let fromBalanceSlot := keccak256(0x0c, 0x1c)
                sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
            }
            // Increment the balance of `to`.
            {
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x1c)
                let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
                if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) {
                    mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
                    revert(0x1c, 0x04)
                }
                sstore(toBalanceSlot, toBalanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
        }
        _afterTokenTransfer(from, to, id);
    }

    /// @dev Equivalent to `_safeTransfer(from, to, id, "")`.
    function _safeTransfer(address from, address to, uint256 id) internal virtual {
        _safeTransfer(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - 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 id, bytes memory data)
        internal
        virtual
    {
        _transfer(address(0), from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`.
    function _safeTransfer(address by, address from, address to, uint256 id) internal virtual {
        _safeTransfer(by, from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    /// - 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 by, address from, address to, uint256 id, bytes memory data)
        internal
        virtual
    {
        _transfer(by, from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    HOOKS FOR OVERRIDING                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Hook that is called before any token transfers, including minting and burning.
    function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {}

    /// @dev Hook that is called after any token transfers, including minting and burning.
    function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {}

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns if `a` has bytecode of non-zero length.
    function _hasCode(address a) private view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := extcodesize(a) // Can handle dirty upper bits.
        }
    }

    /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`.
    /// Reverts if the target does not support the function correctly.
    function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
        private
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the calldata.
            let m := mload(0x40)
            let onERC721ReceivedSelector := 0x150b7a02
            mstore(m, onERC721ReceivedSelector)
            mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.
            mstore(add(m, 0x40), shr(96, shl(96, from)))
            mstore(add(m, 0x60), id)
            mstore(add(m, 0x80), 0x80)
            let n := mload(data)
            mstore(add(m, 0xa0), n)
            if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }
            // Revert if the call reverts.
            if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
                if returndatasize() {
                    // Bubble up the revert if the call reverts.
                    returndatacopy(0x00, 0x00, returndatasize())
                    revert(0x00, returndatasize())
                }
                mstore(m, 0)
            }
            // Load the returndata and compare it.
            if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
                mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

File 12 of 16 : CommitReveal.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

contract CommitReveal {
    error InvalidCommitment(uint256 committedTimestamp);

    uint256 private constant INVALID_COMMITMENT_SELECTOR = 0x31e63ea0;

    uint256 public immutable COMMITMENT_LIFESPAN;
    uint256 public immutable COMMITMENT_DELAY;

    constructor(uint256 commitmentLifespan, uint256 commitmentDelay) {
        COMMITMENT_LIFESPAN = commitmentLifespan;
        COMMITMENT_DELAY = commitmentDelay;
    }

    ///@dev mapping of user to key to commitment hash to timestamp.
    mapping(address user => mapping(bytes32 commitment => uint256 timestamp)) public commitments;

    /**
     * @notice Commit a hash to the contract, to be retrieved and verified after a delay. A commitment is valid only
     *         after COMMITMENT_DELAY seconds have passed, and is only valid for COMMITMENT_LIFESPAN seconds.
     * @param commitment The hash to commit.
     */
    function commit(bytes32 commitment) public {
        commitments[msg.sender][commitment] = block.timestamp;
    }

    /**
     * @dev Assert that a commitment has been made and is within a valid time
     *      window.
     * @param computedCommitmentHash The derived commitment hash to verify.
     */
    function _assertCommittedReveal(bytes32 computedCommitmentHash) internal view {
        // retrieve the timestamp of the commitment (if it exists)
        uint256 retrievedTimestamp = commitments[msg.sender][computedCommitmentHash];
        // compute the time difference
        uint256 timeDiff;
        // unchecked; assume blockchain time is monotonically increasing
        unchecked {
            timeDiff = block.timestamp - retrievedTimestamp;
        }
        uint256 commitmentLifespan = COMMITMENT_LIFESPAN;
        uint256 commitmentDelay = COMMITMENT_DELAY;
        assembly {
            // if the time difference is greater than the commitment lifespan,
            // the commitment has expired
            // if the time difference is less than the commitment delay, the
            // commitment is pending
            let invalidCommitment := or(gt(timeDiff, commitmentLifespan), lt(timeDiff, commitmentDelay))
            if invalidCommitment {
                mstore(0, INVALID_COMMITMENT_SELECTOR)
                mstore(0x20, retrievedTimestamp)
                revert(0x1c, 0x24)
            }
        }
    }
}

File 13 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

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

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

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

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

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

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

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

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

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

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

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

    /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
    /// It is intentionally choosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;

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

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

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

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

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

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

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

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

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

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

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

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

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

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

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

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

File 14 of 16 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

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

    /// @dev Suggested gas stipend for contract receiving ETH
    /// that disallows any storage writes.
    uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    /// Multiply by a small constant (e.g. 2), if needed.
    uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000;

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

    /// @dev Sends `amount` (in wei) ETH to `to`.
    /// Reverts upon failure.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, amount, 0, 0, 0, 0)) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// The `gasStipend` can be set to a low enough value to prevent
    /// storage writes or gas griefing.
    ///
    /// If sending via the normal procedure fails, force sends the ETH by
    /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
    ///
    /// Reverts if the current contract has insufficient balance.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // If insufficient balance, revert.
            if lt(selfbalance(), amount) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(gasStipend, to, amount, 0, 0, 0, 0)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                // We can directly use `SELFDESTRUCT` in the contract creation.
                // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
                if iszero(create(amount, 0x0b, 0x16)) {
                    // For better gas estimation.
                    if iszero(gt(gas(), 1000000)) { revert(0, 0) }
                }
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend
    /// equal to `_GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default
    /// for 99% of cases and can be overriden with the three-argument version of this
    /// function if necessary.
    ///
    /// If sending via the normal procedure fails, force sends the ETH by
    /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
    ///
    /// Reverts if the current contract has insufficient balance.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        // Manually inlined because the compiler doesn't inline functions with branches.
        /// @solidity memory-safe-assembly
        assembly {
            // If insufficient balance, revert.
            if lt(selfbalance(), amount) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(_GAS_STIPEND_NO_GRIEF, to, amount, 0, 0, 0, 0)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                // We can directly use `SELFDESTRUCT` in the contract creation.
                // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
                if iszero(create(amount, 0x0b, 0x16)) {
                    // For better gas estimation.
                    if iszero(gt(gas(), 1000000)) { revert(0, 0) }
                }
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// The `gasStipend` can be set to a low enough value to prevent
    /// storage writes or gas griefing.
    ///
    /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend.
    ///
    /// Note: Does NOT revert upon failure.
    /// Returns whether the transfer of ETH is successful instead.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and check if it succeeded or not.
            success := call(gasStipend, to, amount, 0, 0, 0, 0)
        }
    }

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

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.

            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            // Store the function selector of `transferFrom(address,address,uint256)`.
            mstore(0x0c, 0x23b872dd000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.

            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            // Store the function selector of `balanceOf(address)`.
            mstore(0x0c, 0x70a08231000000000000000000000000)
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Store the function selector of `transferFrom(address,address,uint256)`.
            mstore(0x00, 0x23b872dd)
            // The `amount` argument is already written to the memory word at 0x6c.
            amount := mload(0x60)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            // Store the function selector of `transfer(address,uint256)`.
            mstore(0x00, 0xa9059cbb000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x14, to) // Store the `to` argument.
            // The `amount` argument is already written to the memory word at 0x34.
            amount := mload(0x34)
            // Store the function selector of `transfer(address,uint256)`.
            mstore(0x00, 0xa9059cbb000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            // Store the function selector of `approve(address,uint256)`.
            mstore(0x00, 0x095ea7b3000000000000000000000000)

            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `ApproveFailed()`.
                mstore(0x00, 0x3e3f8f73)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Restore the part of the free memory pointer that was overwritten.
            mstore(0x34, 0)
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            // Store the function selector of `balanceOf(address)`.
            mstore(0x00, 0x70a08231000000000000000000000000)
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

File 15 of 16 : IERC4906.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {IERC165} from "forge-std/interfaces/IERC165.sol";

interface IERC4906 is IERC165 {
    /// @dev This event emits when the metadata of a token is changed.
    /// So that the third-party platforms such as NFT market could
    /// timely update the images and related attributes of the NFT.
    event MetadataUpdate(uint256 _tokenId);

    /// @dev This event emits when the metadata of a range of tokens is changed.
    /// So that the third-party platforms such as NFT market could
    /// timely update the images and related attributes of the NFTs.
    event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}

File 16 of 16 : IERC165.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

interface IERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    /// uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    /// `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

Settings
{
  "remappings": [
    "create2-helpers/=lib/create2-helpers/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc721a/=lib/erc721a/contracts/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/create2-helpers/lib/openzeppelin-contracts/",
    "solady-test/=lib/solady/test/",
    "solady/=lib/solady/src/",
    "solarray/=lib/solarray/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"creatorPayout","type":"address"},{"internalType":"uint256","name":"maxBatchSize","type":"uint256"},{"internalType":"uint24[]","name":"preMintIds","type":"uint24[]"},{"internalType":"address","name":"seaDrop","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyFinalized","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"BatchBurnerNotApprovedForAll","type":"error"},{"inputs":[{"internalType":"uint256","name":"committedTimestamp","type":"uint256"}],"name":"InvalidCommitment","type":"error"},{"inputs":[],"name":"InvalidHex","type":"error"},{"inputs":[],"name":"InvalidPayment","type":"error"},{"inputs":[],"name":"InvalidTimestamp","type":"error"},{"inputs":[],"name":"MaxBatchSizeExceeded","type":"error"},{"inputs":[],"name":"MaximumSupplyExceeded","type":"error"},{"inputs":[],"name":"MintClosed","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NoIdsProvided","type":"error"},{"inputs":[],"name":"NoneAvailable","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"OnlyFinalized","type":"error"},{"inputs":[],"name":"OnlySeadrop","type":"error"},{"inputs":[],"name":"OnlyTokenOwner","type":"error"},{"inputs":[],"name":"OwnerMismatch","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"Unavailable","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","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":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"COMMITMENT_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COMMITMENT_LIFESPAN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_MINT_CLOSE_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SPECIFIC_BATCH_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REROLL_AND_FINALIZE_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REROLL_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bool","name":"onlyFinalized","type":"bool"}],"name":"batchBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"batchFinalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"batchMintSpecific","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"batchReroll","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"oldIds","type":"uint256[]"},{"internalType":"uint256[]","name":"newIds","type":"uint256[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"batchRerollSpecific","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"oldIds","type":"uint256[]"},{"internalType":"uint256[]","name":"newIds","type":"uint256[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"batchRerollSpecificAndFinalize","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"xxyyzz","type":"uint256"},{"internalType":"bool","name":"onlyFinalized","type":"bool"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"commit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"commitments","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"computeBatchCommitment","outputs":[{"internalType":"bytes32","name":"commitmentHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"computeCommitment","outputs":[{"internalType":"bytes32","name":"committmentHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"configureSeaDrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"finalizers","outputs":[{"internalType":"address","name":"finalizer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getMintStats","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isFinalized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mintSeaDrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"mintSpecific","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mintTo","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"numBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipHandoverValidFor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"oldId","type":"uint256"}],"name":"reroll","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"oldId","type":"uint256"},{"internalType":"uint256","name":"newId","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"rerollSpecific","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"oldId","type":"uint256"},{"internalType":"uint256","name":"newId","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"rerollSpecificAndFinalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

61016060405234801562000011575f80fd5b50604051620042cd380380620042cd8339810160408190526200003491620002d4565b62015180608052603060a0528084868581818181620000538262000156565b60c05250620000664262127500620003e4565b60e05250506001600160a01b038085166101005242610140528316610120527fd7aca75208b9be5ffc04c6a01922020ffd62b55e68e502e317f5344960279af85f80a1505050505f5b82518110156200012857620000ec86848381518110620000d357620000d36200040a565b602002602001015162ffffff166200019160201b60201c565b6200011f8382815181106200010557620001056200040a565b602002602001015162ffffff16876200023b60201b60201c565b600101620000af565b505051600280546001600160801b031663ffffffff909216600160801b02919091179055506200041e915050565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6001600160a01b039091169081620001b05763ea553b345f526004601cfd5b805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b15620001e35763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff81166200020e576301336cea5f526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a45050565b5f828152600160208181526040832080546001600160a01b0386166001600160a01b0319909116179055673ec412a9852d173d60c11b601c5290912083018301805460a081811c90931890921b90911890555050565b80516001600160a01b0381168114620002a8575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b805162ffffff81168114620002a8575f80fd5b5f805f805f60a08688031215620002e9575f80fd5b620002f48662000291565b945060206200030581880162000291565b6040880151606089015191965094506001600160401b038082111562000329575f80fd5b818901915089601f8301126200033d575f80fd5b815181811115620003525762000352620002ad565b8060051b604051601f19603f830116810181811085821117156200037a576200037a620002ad565b60405291825284820192508381018501918c83111562000398575f80fd5b938501935b82851015620003c157620003b185620002c1565b845293850193928501926200039d565b809750505050505050620003d86080870162000291565b90509295509295909350565b808201808211156200040457634e487b7160e01b5f52601160045260245ffd5b92915050565b634e487b7160e01b5f52603260045260245ffd5b60805160a05160c05160e051610100516101205161014051613e25620004a85f395f61133901525f6114b501525f818161126e015261140c01525f81816106f40152818161136301528181611f7d015261228f01525f818161047c01528181611cd401526122e901525f81816105160152611d7501525f81816104bd0152611d540152613e255ff3fe60806040526004361061037f575f3560e01c8063715018a6116101d3578063c002d23d116100fd578063dd686e261161009d578063f04e283e1161006d578063f04e283e14610a2c578063f14fcbc814610a3f578063f2fde38b14610a74578063fee81cf414610a87575f80fd5b8063dd686e2614610905578063e8a3d485146109d1578063e985e9c5146109e5578063ea08b46514610a19575f80fd5b8063d52079b4116100d8578063d52079b414610951578063d5abeb011461098b578063d7533f02146109a1578063d8176369146109be575f80fd5b8063c002d23d14610905578063c87b56dd1461091f578063ccedf5721461093e575f80fd5b80639fac68cb11610173578063ad7556d711610143578063ad7556d7146108ad578063afb34abe146108cc578063b88d4fde146108df578063b8a49eba146108f2575f80fd5b80639fac68cb14610849578063a0712d6814610868578063a22cb4651461087b578063ad3554661461089a575f80fd5b80638b1592b5116101ae5780638b1592b5146107ca5780638da5cb5b146107fd57806395d89b41146103f35780639f51758e14610830575f80fd5b8063715018a6146107165780637e92a4231461071e578063840e15d41461075f575f80fd5b806323b872dd116102b45780634e9edf1c1161025457806364869dad1161022457806364869dad146106915780636cd473cb146106b057806370a08231146106c45780637112ca4f146106e3575f80fd5b80634e9edf1c1461063d57806354d1f13d1461065757806360abc14b1461065f5780636352211e14610672575f80fd5b806333727c4d1161028f57806333727c4d146105d75780633ccfd60b146105f657806342842e0e1461060a578063449a52f81461061d575f80fd5b806323b872dd14610586578063256929621461059957806327e99a5c146105a1575f80fd5b80630affb8341161031f5780631249c58b116102fa5780631249c58b1461053857806318160ddd146105405780631c19c215146105545780631ced131814610567575f80fd5b80630affb834146104ac57806311a040ac146104df57806311a733f614610505575f80fd5b806306fdde031161035a57806306fdde03146103f3578063081812fc14610414578063095ea7b3146104585780630a157d9e1461046b575f80fd5b806301ffc9a71461038a57806305261aea146103be57806306740ff4146103d3575f80fd5b3661038657005b5f80fd5b348015610395575f80fd5b506103a96103a436600461316a565b610ab8565b60405190151581526020015b60405180910390f35b6103d16103cc3660046131a9565b610af5565b005b6103e66103e1366004613208565b610b13565b6040516103b59190613276565b3480156103fe575f80fd5b50610407610b57565b6040516103b591906132dd565b34801561041f575f80fd5b5061043361042e3660046131a9565b610b6e565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103b5565b6103d1610466366004613350565b610bd1565b348015610476575f80fd5b5061049e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016103b5565b3480156104b7575f80fd5b5061049e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104ea575f80fd5b506002546fffffffffffffffffffffffffffffffff1661049e565b348015610510575f80fd5b5061049e7f000000000000000000000000000000000000000000000000000000000000000081565b61049e610be0565b34801561054b575f80fd5b5061049e610c04565b61049e6105623660046131a9565b610c53565b348015610572575f80fd5b506103d1610581366004613387565b610c6f565b6103d16105943660046133d7565b610f4b565b6103d1611098565b3480156105ac575f80fd5b5061049e6105bb366004613410565b60189290921b62ffffff91909116175f52602052604060092090565b3480156105e2575f80fd5b506103a96105f13660046131a9565b6110e5565b348015610601575f80fd5b506103d161112c565b6103d16106183660046133d7565b611149565b61063061062b366004613350565b611175565b6040516103b59190613440565b348015610648575f80fd5b5061049e6612a6d8e112200081565b6103d1611188565b6103e661066d366004613477565b6111c1565b34801561067d575f80fd5b5061043361068c3660046131a9565b6111f8565b34801561069c575f80fd5b506103d16106ab366004613350565b611256565b3480156106bb575f80fd5b506103d1611314565b3480156106cf575f80fd5b5061049e6106de3660046134bf565b6116d6565b3480156106ee575f80fd5b5061049e7f000000000000000000000000000000000000000000000000000000000000000081565b6103d1611723565b348015610729575f80fd5b506104336107383660046131a9565b60016020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561076a575f80fd5b506107af6107793660046134bf565b506002545f917001000000000000000000000000000000009091046fffffffffffffffffffffffffffffffff1690630100000090565b604080519384526020840192909252908201526060016103b5565b3480156107d5575f80fd5b5061049e6107e4366004613350565b5f60208181529281526040808220909352908152205481565b348015610808575f80fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754610433565b34801561083b575f80fd5b5061049e65e35fa931a00081565b348015610854575f80fd5b506103d16108633660046134d8565b611736565b6106306108763660046131a9565b6117fc565b348015610886575f80fd5b506103d1610895366004613502565b611808565b6103d16108a836600461352a565b61185b565b3480156108b8575f80fd5b5061049e6108c7366004613569565b61189f565b6103d16108da3660046135bf565b6118cd565b6103d16108ed3660046135df565b6118e2565b61063061090036600461352a565b611935565b348015610910575f80fd5b5061049e6611c37937e0800081565b34801561092a575f80fd5b506104076109393660046131a9565b6119ec565b6103d161094c366004613672565b611a2e565b34801561095c575f80fd5b5060025470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1661049e565b348015610996575f80fd5b50630100000061049e565b3480156109ac575f80fd5b506040516202a30081526020016103b5565b6103d16109cc366004613672565b611a4a565b3480156109dc575f80fd5b50610407611ae0565b3480156109f0575f80fd5b506103a96109ff36600461369b565b601c52670a5a2e7a000000006008525f526030600c205490565b6103e6610a27366004613208565b611b11565b6103d1610a3a3660046134bf565b611b4b565b348015610a4a575f80fd5b506103d1610a593660046131a9565b335f9081526020818152604080832093835292905220429055565b6103d1610a823660046134bf565b611b85565b348015610a92575f80fd5b5061049e610aa13660046134bf565b63389a75e1600c9081525f91909152602090205490565b5f610aef826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f8214176349064906821417631890fe8e9091141790565b92915050565b610b076611c37937e080006001611bab565b610b1081611be6565b50565b6060610b288686868665e35fa931a000611c99565b5f610b353386868661189f565b9050610b4081611d36565b610b4c87878787611db2565b979650505050505050565b6060602080526606585859595a5a60465260806020f35b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c526020812082018201805473ffffffffffffffffffffffffffffffffffffffff16610bc75763ceea21b65f526004601cfd5b6001015492915050565b610bdc338383611ecb565b5050565b5f80610bec6001611f7a565b90505f610bf882612023565b9050610aef3382612079565b6002545f90610c3c906fffffffffffffffffffffffffffffffff808216917001000000000000000000000000000000009004166136c3565b6fffffffffffffffffffffffffffffffff16905090565b5f610c6565e35fa931a0006001611bab565b610aef8233612142565b5f829003610ca9576040517fe663430d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610cf984845f818110610cbf57610cbf613718565b905060200201355f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015490565b9050808215610d505773ffffffffffffffffffffffffffffffffffffffff821015610d50576040517f532201f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314610dc257610d8c8133601c52670a5a2e7a000000006008525f526030600c205490565b610dc2576040517fcbd6109100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280546fffffffffffffffffffffffffffffffff80821663ffffffff881601167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116179055610e2985855f81610e1d57610e1d613718565b9050602002013561216b565b60015b84811015610f43575f868683818110610e4757610e47613718565b905060200201359050610e87815f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015490565b93508373ffffffffffffffffffffffffffffffffffffffff80821690851614610edc576040517fa8c8162300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8515610f305773ffffffffffffffffffffffffffffffffffffffff851015610f30576040517f532201f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f398261216b565b5050600101610e2c565b505050505050565b5f8181527f7d8825530a5a2e7a0000000000000000000000000000000000000000000000003317601c526020902081018101805473ffffffffffffffffffffffffffffffffffffffff9485169493841693811691908286148302610fc85782610fbb5763ceea21b65f526004601cfd5b63a11481005f526004601cfd5b84610fda5763ea553b345f526004601cfd5b855f528160010154925082331486331417611006576030600c205461100657634b6e7f185f526004601cfd5b8215611013575f82600101555b85851818905550601c600c81812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555f84905220805460010163ffffffff8116611069576301336cea5f526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a45b505050565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b5f6110ef82612175565b610aef825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460a01c60011490565b6111346121b2565b5f8081828347335af1610b10573d81823e3d81fd5b611154838383610f4b565b813b156110935761109383838360405180602001604052805f8152506121e7565b6060611181838361226c565b9392505050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b60606111cd848461228d565b5f6111da3386868661189f565b90506111e581611d36565b6111ef8585612352565b95945050505050565b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015473ffffffffffffffffffffffffffffffffffffffff16806112515763ceea21b65f526004601cfd5b919050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146112c5576040517fa8eb05d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280546fffffffffffffffffffffffffffffffff80821670010000000000000000000000000000000092839004821685019182169283021790925561130e908490849061244b565b50505050565b61131c6121b2565b6040805160c0810182526611c37937e08000815265ffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116602083019081527f0000000000000000000000000000000000000000000000000000000000000000821683850190815261ffff606085018181526103e860808701908152600160a0880190815297517f01308e65000000000000000000000000000000000000000000000000000000008152965169ffffffffffffffffffff166004880152935185166024870152915190931660448501525182166064840152511660848201529051151560a48201527f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8216906301308e659060c4015f604051808303815f87803b158015611464575f80fd5b505af1158015611476573d5f803e3d5ffd5b50506040517f12738db800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166004830152841692506312738db891506024015f604051808303815f87803b158015611500575f80fd5b505af1158015611512573d5f803e3d5ffd5b50506040517f8e7d1e4300000000000000000000000000000000000000000000000000000000815271a26b00c1f0df003000390027140000faa71960048201526001602482015273ffffffffffffffffffffffffffffffffffffffff84169250638e7d1e4391506044015f604051808303815f87803b158015611593575f80fd5b505af11580156115a5573d5f803e3d5ffd5b50506040517f7f2a5cca00000000000000000000000000000000000000000000000000000000815273f408bee3443d0397e2c1cde588fb060ac657006f60048201526001602482015273ffffffffffffffffffffffffffffffffffffffff84169250637f2a5cca91506044015f604051808303815f87803b158015611628575f80fd5b505af115801561163a573d5f803e3d5ffd5b50506040517f7f2a5cca00000000000000000000000000000000000000000000000000000000815273e3d3d0ed702504e19825f44bc6542ff2ec45cb9a60048201526001602482015273ffffffffffffffffffffffffffffffffffffffff84169250637f2a5cca91506044015f604051808303815f87803b1580156116bd575f80fd5b505af11580156116cf573d5f803e3d5ffd5b5050505050565b5f816116e957638f4eb6045f526004601cfd5b7f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52815f5263ffffffff601c600c2054169050919050565b61172b6121b2565b6117345f6124de565b565b600280546fffffffffffffffffffffffffffffffff808216600101167fffffffffffffffffffffffffffffffff0000000000000000000000000000000090911617905580156117f2576117bc825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460a01c60011490565b6117f2576040517f532201f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bdc3383612543565b6060610aef338361226c565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b61186c6611c37937e0800082611bab565b5f5b818110156110935761189783838381811061188b5761188b613718565b90506020020135611be6565b60010161186e565b5f6040518360051b8086833781205f969096526020959095525060409081526060600c209390525090919050565b6118d76001611f7a565b50610bdc828261264a565b6118ed858585610f4b565b833b156116cf576116cf85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506121e792505050565b606061194765e35fa931a00083611bab565b335f8367ffffffffffffffff81111561196257611962613745565b60405190808252806020026020018201604052801561198b578160200160208202803683370190505b5090505f5b848110156119e3576119ba8686838181106119ad576119ad613718565b9050602002013584612142565b8282815181106119cc576119cc613718565b602090810291909101015260019283019201611990565b50949350505050565b60606119f782612175565b611a08611a03836126f1565b6128a2565b604051602001611a189190613772565b6040516020818303038152906040529050919050565b611a3f65e35fa931a0006001611bab565b6110938383836128af565b611a5c6612a6d8e11220006001611bab565b611a678383836128af565b5f828152600160208181526040832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790557f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5290912083018301805460a081811c90931890921b9091189055505050565b6060611aed611a036128cb565b604051602001611afd9190613772565b604051602081830303815290604052905090565b6060611b27868686866612a6d8e1122000611c99565b5f611b343386868661189f565b9050611b3f81611d36565b610b4c878787876128eb565b611b536121b2565b63389a75e1600c52805f526020600c208054421115611b7957636f5e88185f526004601cfd5b5f9055610b10816124de565b611b8d6121b2565b8060601b611ba257637448fbae5f526004601cfd5b610b10816124de565b8082023414610bdc576040517f3c6b4b2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bef81612a6a565b5f818152600160208181526040832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790557f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5290912082018201805460a081811c90931890921b90911890556040518181527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a150565b838214611cd2576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000841115611d2c576040517f7a7e96df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116cf8482611bab565b335f90815260208181526040808320848452909152902054428190037f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000818311818410178015610f43576331e63ea05f52846020526024601cfd5b60605f8467ffffffffffffffff811115611dce57611dce613745565b604051908082528060200260200182016040528015611df7578160200160208202803683370190505b5090505f805b86811015611e7757611e3f888883818110611e1a57611e1a613718565b90506020020135878784818110611e3357611e33613718565b90506020020135612b39565b15611e6f576001838281518110611e5857611e58613718565b911515602092830291909101909101526001909101905b600101611dfd565b50805f03611eb1576040517fc17b61ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ec165e35fa931a00082612b6a565b5095945050505050565b5f1960601c82811692508381169350815f52837f7d8825530a5a2e7a00000000000000000000000000000000000000000000000017601c5260205f208201820180548216915081611f235763ceea21b65f526004601cfd5b818514851517611f4757815f526030600c2054611f4757634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a450505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000421115611fd5576040517f589ed34b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fe66611c37937e0800083611bab565b50600280546fffffffffffffffffffffffffffffffff70010000000000000000000000000000000080830482169094018116938402911617905590565b5f818152446020526040600c2062ffffff165b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015415610aef5760010162ffffff16612036565b73ffffffffffffffffffffffffffffffffffffffff90911690816120a45763ea553b345f526004601cfd5b805f527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260205f208101810180548060601b156120eb5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff8116612115576301336cea5f526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a45050565b5f61214c83612a6a565b6121558361216b565b5f61215f83612023565b90506111813382612079565b610b105f82612543565b62ffffff811115610b10576040517fcbbc48a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314611734576382b429005f526004601cfd5b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a0840152801561222e578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1612253573d1561224f573d5f803e3d5ffd5b5f83525b508060e01b825114610f435763d1a57ed65f526004601cfd5b60605f61227883611f7a565b905061228584848361244b565b949350505050565b7f00000000000000000000000000000000000000000000000000000000000000004211156122e7576040517f589ed34b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000811115612341576040517f7a7e96df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bdc816611c37937e08000611bab565b60605f8267ffffffffffffffff81111561236e5761236e613745565b604051908082528060200260200182016040528015612397578160200160208202803683370190505b5090505f805b848110156123fe576123c68686838181106123ba576123ba613718565b90506020020135612b81565b156123f65760018382815181106123df576123df613718565b911515602092830291909101909101526001909101905b60010161239d565b50805f03612438576040517fc17b61ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61244181612bda565b5090949350505050565b60605f8367ffffffffffffffff81111561246757612467613745565b604051908082528060200260200182016040528015612490578160200160208202803683370190505b5090505f5b848110156119e3575f6124a785612023565b90506124b38782612079565b808383815181106124c6576124c6613718565b60209081029190910101525060019384019301612495565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f61254d826111f8565b9050505f81815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c5260209091208201820180549193821691826125b45763ceea21b65f526004601cfd5b825f528160010154808614848714178615176125e1576030600c20546125e157634b6e7f185f526004601cfd5b80156125ee575f83600101555b5082189055601c600c2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055815f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4505050565b3360181b62ffffff8316175f526020819052604060092061266a83612175565b61267381611d36565b6126b0835f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460a01c60011490565b156126e7576040517f475a253500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110933384612079565b606061273a6040518060400160405280600481526020017f6e616d650000000000000000000000000000000000000000000000000000000081525061273584612c2d565b612c4a565b6127ae6040518060400160405280600d81526020017f65787465726e616c5f6c696e6b000000000000000000000000000000000000008152506040518060400160405280601281526020017f68747470733a2f2f787879797a7a2e6172740000000000000000000000000000815250612c4a565b6128056040518060400160405280600b81526020017f6465736372697074696f6e0000000000000000000000000000000000000000008152506040518060a0016040528060648152602001613d4760649139612c4a565b6128476040518060400160405280600581526020017f696d61676500000000000000000000000000000000000000000000000000000081525061273587612c76565b61288e6040518060400160405280600a81526020017f617474726962757465730000000000000000000000000000000000000000000081525061288988612c94565b612e99565b604051602001611a189594939291906137b6565b6060610aef825f80612eae565b6128b883612a6a565b6128c18361216b565b611093828261264a565b60606040518060a00160405280607a8152602001613dab607a9139905090565b60605f8467ffffffffffffffff81111561290757612907613745565b604051908082528060200260200182016040528015612930578160200160208202803683370190505b5090505f805b86811015612a1f57612953888883818110611e1a57611e1a613718565b15612a17576129ec86868381811061296d5761296d613718565b602090810292909201355f81815260018085526040822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790557f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52939020810101805460a081811c90941890931b90921890915550565b6001838281518110612a0057612a00613718565b911515602092830291909101909101526001909101905b600101612936565b50805f03612a59576040517fc17b61ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ec16612a6d8e112200082612b6a565b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c526020902081018101548073ffffffffffffffffffffffffffffffffffffffff811115612aea576040517f475a253500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314611093576040517fcdf1f8f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612b4383612a6a565b612b4c82612b81565b15612b6257612b5a8361216b565b506001610aef565b505f92915050565b818102348181039114611093576110933382612fae565b5f612b8b82612175565b5f8281527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020820182015415612bc857505f919050565b612bd23383612079565b506001919050565b6002805463ffffffff6fffffffffffffffffffffffffffffffff70010000000000000000000000000000000080840482168601928316029216919091179091555f90610aef6611c37937e0800084612b6a565b6060612c3a826003612fc7565b604051602001611a1891906138bc565b60608282604051602001612c5f929190613900565b604051602081830303815290604052905092915050565b6060612c84611a038361306b565b604051602001611a189190613989565b60605f612cde6040518060400160405280600581526020017f436f6c6f72000000000000000000000000000000000000000000000000000000815250612cd985612c2d565b613088565b9050612ce9836110e5565b15612dfc575f612d636040518060400160405280600981526020017f46696e616c697a656400000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f5965730000000000000000000000000000000000000000000000000000000000815250613088565b604080518082018252600981527f46696e616c697a657200000000000000000000000000000000000000000000006020808301919091525f8881526001909152919091205491925083918391612dd291612cd99073ffffffffffffffffffffffffffffffffffffffff1661309d565b604051602001612de4939291906139cd565b60405160208183030381529060405292505050919050565b80612e716040518060400160405280600981526020017f46696e616c697a656400000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f4e6f000000000000000000000000000000000000000000000000000000000000815250613088565b604051602001612e82929190613a95565b604051602081830303815290604052915050919050565b60608282604051602001612c5f929190613b3f565b606083518015612fa6576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c16515f53603f81600c1c1651600153603f8160061c1651600253603f811651600353505f518252600482019150808210612f1e576020016040527f3d3d00000000000000000000000000000000000000000000000000000000000060038406600204808303919091525f8615159091029182900352900382525b509392505050565b5f805f8084865af1610bdc5763b12d13eb5f526004601cfd5b6060601f1960428360011b0116604051019050602081016040525f8152806f30313233343536373839616263646566600f528283018203600119855b600f811651948201946001860153600f8160041c1651855360081c84830361300357801561303857632194895a5f526004601cfd5b5050508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910190815292915050565b6060613078826003612fc7565b604051602001611a189190613bbf565b60608282604051602001612c5f929190613c9c565b60606130a8826130df565b805161307882526002017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe90910190815292915050565b60606040519050608081016040526f30313233343536373839616263646566600f5260028101905060288152602081015f60288201528260601b92505f5b808101820184821a600f81165160018301538060041c518253505060018101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed0161311d575050919050565b5f6020828403121561317a575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611181575f80fd5b5f602082840312156131b9575f80fd5b5035919050565b5f8083601f8401126131d0575f80fd5b50813567ffffffffffffffff8111156131e7575f80fd5b6020830191508360208260051b8501011115613201575f80fd5b9250929050565b5f805f805f6060868803121561321c575f80fd5b853567ffffffffffffffff80821115613233575f80fd5b61323f89838a016131c0565b90975095506020880135915080821115613257575f80fd5b50613264888289016131c0565b96999598509660400135949350505050565b602080825282518282018190525f9190848201906040850190845b818110156132af578351151583529284019291840191600101613291565b50909695505050505050565b5f5b838110156132d55781810151838201526020016132bd565b50505f910152565b602081525f82518060208401526132fb8160408501602087016132bb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611251575f80fd5b5f8060408385031215613361575f80fd5b61336a8361332d565b946020939093013593505050565b80358015158114611251575f80fd5b5f805f60408486031215613399575f80fd5b833567ffffffffffffffff8111156133af575f80fd5b6133bb868287016131c0565b90945092506133ce905060208501613378565b90509250925092565b5f805f606084860312156133e9575f80fd5b6133f28461332d565b92506134006020850161332d565b9150604084013590509250925092565b5f805f60608486031215613422575f80fd5b61342b8461332d565b95602085013595506040909401359392505050565b602080825282518282018190525f9190848201906040850190845b818110156132af5783518352928401929184019160010161345b565b5f805f60408486031215613489575f80fd5b833567ffffffffffffffff81111561349f575f80fd5b6134ab868287016131c0565b909790965060209590950135949350505050565b5f602082840312156134cf575f80fd5b6111818261332d565b5f80604083850312156134e9575f80fd5b823591506134f960208401613378565b90509250929050565b5f8060408385031215613513575f80fd5b61351c8361332d565b91506134f960208401613378565b5f806020838503121561353b575f80fd5b823567ffffffffffffffff811115613551575f80fd5b61355d858286016131c0565b90969095509350505050565b5f805f806060858703121561357c575f80fd5b6135858561332d565b9350602085013567ffffffffffffffff8111156135a0575f80fd5b6135ac878288016131c0565b9598909750949560400135949350505050565b5f80604083850312156135d0575f80fd5b50508035926020909101359150565b5f805f805f608086880312156135f3575f80fd5b6135fc8661332d565b945061360a6020870161332d565b935060408601359250606086013567ffffffffffffffff8082111561362d575f80fd5b818801915088601f830112613640575f80fd5b81358181111561364e575f80fd5b89602082850101111561365f575f80fd5b9699959850939650602001949392505050565b5f805f60608486031215613684575f80fd5b505081359360208301359350604090920135919050565b5f80604083850312156136ac575f80fd5b6136b58361332d565b91506134f96020840161332d565b6fffffffffffffffffffffffffffffffff828116828216039080821115613711577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081525f82516137a981601d8501602087016132bb565b91909101601d0192915050565b7f7b0000000000000000000000000000000000000000000000000000000000000081525f86516137ed816001850160208b016132bb565b80830190507f2c00000000000000000000000000000000000000000000000000000000000000806001830152875161382c816002850160208c016132bb565b600292019182018190528651613849816003850160208b016132bb565b600392019182018190528551613866816004850160208a016132bb565b600492019182015283516138818160058401602088016132bb565b016138ae600582017f7d000000000000000000000000000000000000000000000000000000000000009052565b600601979650505050505050565b7f230000000000000000000000000000000000000000000000000000000000000081525f82516138f38160018501602087016132bb565b9190910160010192915050565b5f7f220000000000000000000000000000000000000000000000000000000000000080835284516139388160018601602089016132bb565b7f223a22000000000000000000000000000000000000000000000000000000000060019185019182015284516139758160048401602089016132bb565b016004810191909152600501949350505050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000081525f82516139c081601a8501602087016132bb565b91909101601a0192915050565b7f5b0000000000000000000000000000000000000000000000000000000000000081525f8451613a048160018501602089016132bb565b80830190507f2c000000000000000000000000000000000000000000000000000000000000008060018301528551613a43816002850160208a016132bb565b60029201918201528351613a5e8160038401602088016132bb565b7f5d000000000000000000000000000000000000000000000000000000000000006003929091019182015260040195945050505050565b7f5b0000000000000000000000000000000000000000000000000000000000000081525f8351613acc8160018501602088016132bb565b7f2c000000000000000000000000000000000000000000000000000000000000006001918401918201528351613b098160028401602088016132bb565b7f5d0000000000000000000000000000000000000000000000000000000000000060029290910191820152600301949350505050565b7f220000000000000000000000000000000000000000000000000000000000000081525f8351613b768160018501602088016132bb565b7f223a0000000000000000000000000000000000000000000000000000000000006001918401918201528351613bb38160038401602088016132bb565b01600301949350505050565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222077696474683d2236393022206865696768743d223639302260208201527f3e3c726563742077696474683d2236393022206865696768743d22363930222060408201527f66696c6c3d22230000000000000000000000000000000000000000000000000060608201525f8251613c688160678501602087016132bb565b7f22202f3e3c2f7376673e000000000000000000000000000000000000000000006067939091019283015250607101919050565b7f7b2274726169745f74797065223a22000000000000000000000000000000000081525f8351613cd381600f8501602088016132bb565b7f222c2276616c7565223a22000000000000000000000000000000000000000000600f918401918201528351613d1081601a8401602088016132bb565b7f227d000000000000000000000000000000000000000000000000000000000000601a9290910191820152601c0194935050505056fe50726f6f66206f6620636f6c6f722e20585859595a5a206973206120636f6c6c656374696f6e206f662066756c6c79206f6e636861696e2c20756e697175652c20636f6d706f7361626c652c20616e6420636f6c6c65637461626c6520636f6c6f72732e7b226e616d65223a22585859595a5a222c226465736372697074696f6e223a22436f6c6c65637469626c652c20636f6d706f7361626c652c20616e6420756e69717565206f6e636861696e20636f6c6f72732e222c2265787465726e616c5f6c696e6b223a2268747470733a2f2f787879797a7a2e617274227d0000000000000000000000007039813983ba47a5a46b19f3a269aef5c6c75abf0000000000000000000000007ade04fa0cbe2167e8bff758f48879bd0c6fff92000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000005ea00ac477b1030ce78506496e8c2de24bf5000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000006969690000000000000000000000000000000000000000000000000000000000ff6000000000000000000000000000000000000000000000000000000000000000ff00

Deployed Bytecode

0x60806040526004361061037f575f3560e01c8063715018a6116101d3578063c002d23d116100fd578063dd686e261161009d578063f04e283e1161006d578063f04e283e14610a2c578063f14fcbc814610a3f578063f2fde38b14610a74578063fee81cf414610a87575f80fd5b8063dd686e2614610905578063e8a3d485146109d1578063e985e9c5146109e5578063ea08b46514610a19575f80fd5b8063d52079b4116100d8578063d52079b414610951578063d5abeb011461098b578063d7533f02146109a1578063d8176369146109be575f80fd5b8063c002d23d14610905578063c87b56dd1461091f578063ccedf5721461093e575f80fd5b80639fac68cb11610173578063ad7556d711610143578063ad7556d7146108ad578063afb34abe146108cc578063b88d4fde146108df578063b8a49eba146108f2575f80fd5b80639fac68cb14610849578063a0712d6814610868578063a22cb4651461087b578063ad3554661461089a575f80fd5b80638b1592b5116101ae5780638b1592b5146107ca5780638da5cb5b146107fd57806395d89b41146103f35780639f51758e14610830575f80fd5b8063715018a6146107165780637e92a4231461071e578063840e15d41461075f575f80fd5b806323b872dd116102b45780634e9edf1c1161025457806364869dad1161022457806364869dad146106915780636cd473cb146106b057806370a08231146106c45780637112ca4f146106e3575f80fd5b80634e9edf1c1461063d57806354d1f13d1461065757806360abc14b1461065f5780636352211e14610672575f80fd5b806333727c4d1161028f57806333727c4d146105d75780633ccfd60b146105f657806342842e0e1461060a578063449a52f81461061d575f80fd5b806323b872dd14610586578063256929621461059957806327e99a5c146105a1575f80fd5b80630affb8341161031f5780631249c58b116102fa5780631249c58b1461053857806318160ddd146105405780631c19c215146105545780631ced131814610567575f80fd5b80630affb834146104ac57806311a040ac146104df57806311a733f614610505575f80fd5b806306fdde031161035a57806306fdde03146103f3578063081812fc14610414578063095ea7b3146104585780630a157d9e1461046b575f80fd5b806301ffc9a71461038a57806305261aea146103be57806306740ff4146103d3575f80fd5b3661038657005b5f80fd5b348015610395575f80fd5b506103a96103a436600461316a565b610ab8565b60405190151581526020015b60405180910390f35b6103d16103cc3660046131a9565b610af5565b005b6103e66103e1366004613208565b610b13565b6040516103b59190613276565b3480156103fe575f80fd5b50610407610b57565b6040516103b591906132dd565b34801561041f575f80fd5b5061043361042e3660046131a9565b610b6e565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103b5565b6103d1610466366004613350565b610bd1565b348015610476575f80fd5b5061049e7f000000000000000000000000000000000000000000000000000000000000000581565b6040519081526020016103b5565b3480156104b7575f80fd5b5061049e7f000000000000000000000000000000000000000000000000000000000001518081565b3480156104ea575f80fd5b506002546fffffffffffffffffffffffffffffffff1661049e565b348015610510575f80fd5b5061049e7f000000000000000000000000000000000000000000000000000000000000003081565b61049e610be0565b34801561054b575f80fd5b5061049e610c04565b61049e6105623660046131a9565b610c53565b348015610572575f80fd5b506103d1610581366004613387565b610c6f565b6103d16105943660046133d7565b610f4b565b6103d1611098565b3480156105ac575f80fd5b5061049e6105bb366004613410565b60189290921b62ffffff91909116175f52602052604060092090565b3480156105e2575f80fd5b506103a96105f13660046131a9565b6110e5565b348015610601575f80fd5b506103d161112c565b6103d16106183660046133d7565b611149565b61063061062b366004613350565b611175565b6040516103b59190613440565b348015610648575f80fd5b5061049e6612a6d8e112200081565b6103d1611188565b6103e661066d366004613477565b6111c1565b34801561067d575f80fd5b5061043361068c3660046131a9565b6111f8565b34801561069c575f80fd5b506103d16106ab366004613350565b611256565b3480156106bb575f80fd5b506103d1611314565b3480156106cf575f80fd5b5061049e6106de3660046134bf565b6116d6565b3480156106ee575f80fd5b5061049e7f00000000000000000000000000000000000000000000000000000000649dd9ef81565b6103d1611723565b348015610729575f80fd5b506104336107383660046131a9565b60016020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561076a575f80fd5b506107af6107793660046134bf565b506002545f917001000000000000000000000000000000009091046fffffffffffffffffffffffffffffffff1690630100000090565b604080519384526020840192909252908201526060016103b5565b3480156107d5575f80fd5b5061049e6107e4366004613350565b5f60208181529281526040808220909352908152205481565b348015610808575f80fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754610433565b34801561083b575f80fd5b5061049e65e35fa931a00081565b348015610854575f80fd5b506103d16108633660046134d8565b611736565b6106306108763660046131a9565b6117fc565b348015610886575f80fd5b506103d1610895366004613502565b611808565b6103d16108a836600461352a565b61185b565b3480156108b8575f80fd5b5061049e6108c7366004613569565b61189f565b6103d16108da3660046135bf565b6118cd565b6103d16108ed3660046135df565b6118e2565b61063061090036600461352a565b611935565b348015610910575f80fd5b5061049e6611c37937e0800081565b34801561092a575f80fd5b506104076109393660046131a9565b6119ec565b6103d161094c366004613672565b611a2e565b34801561095c575f80fd5b5060025470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1661049e565b348015610996575f80fd5b50630100000061049e565b3480156109ac575f80fd5b506040516202a30081526020016103b5565b6103d16109cc366004613672565b611a4a565b3480156109dc575f80fd5b50610407611ae0565b3480156109f0575f80fd5b506103a96109ff36600461369b565b601c52670a5a2e7a000000006008525f526030600c205490565b6103e6610a27366004613208565b611b11565b6103d1610a3a3660046134bf565b611b4b565b348015610a4a575f80fd5b506103d1610a593660046131a9565b335f9081526020818152604080832093835292905220429055565b6103d1610a823660046134bf565b611b85565b348015610a92575f80fd5b5061049e610aa13660046134bf565b63389a75e1600c9081525f91909152602090205490565b5f610aef826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f8214176349064906821417631890fe8e9091141790565b92915050565b610b076611c37937e080006001611bab565b610b1081611be6565b50565b6060610b288686868665e35fa931a000611c99565b5f610b353386868661189f565b9050610b4081611d36565b610b4c87878787611db2565b979650505050505050565b6060602080526606585859595a5a60465260806020f35b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c526020812082018201805473ffffffffffffffffffffffffffffffffffffffff16610bc75763ceea21b65f526004601cfd5b6001015492915050565b610bdc338383611ecb565b5050565b5f80610bec6001611f7a565b90505f610bf882612023565b9050610aef3382612079565b6002545f90610c3c906fffffffffffffffffffffffffffffffff808216917001000000000000000000000000000000009004166136c3565b6fffffffffffffffffffffffffffffffff16905090565b5f610c6565e35fa931a0006001611bab565b610aef8233612142565b5f829003610ca9576040517fe663430d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610cf984845f818110610cbf57610cbf613718565b905060200201355f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015490565b9050808215610d505773ffffffffffffffffffffffffffffffffffffffff821015610d50576040517f532201f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314610dc257610d8c8133601c52670a5a2e7a000000006008525f526030600c205490565b610dc2576040517fcbd6109100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280546fffffffffffffffffffffffffffffffff80821663ffffffff881601167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116179055610e2985855f81610e1d57610e1d613718565b9050602002013561216b565b60015b84811015610f43575f868683818110610e4757610e47613718565b905060200201359050610e87815f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015490565b93508373ffffffffffffffffffffffffffffffffffffffff80821690851614610edc576040517fa8c8162300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8515610f305773ffffffffffffffffffffffffffffffffffffffff851015610f30576040517f532201f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f398261216b565b5050600101610e2c565b505050505050565b5f8181527f7d8825530a5a2e7a0000000000000000000000000000000000000000000000003317601c526020902081018101805473ffffffffffffffffffffffffffffffffffffffff9485169493841693811691908286148302610fc85782610fbb5763ceea21b65f526004601cfd5b63a11481005f526004601cfd5b84610fda5763ea553b345f526004601cfd5b855f528160010154925082331486331417611006576030600c205461100657634b6e7f185f526004601cfd5b8215611013575f82600101555b85851818905550601c600c81812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555f84905220805460010163ffffffff8116611069576301336cea5f526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a45b505050565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b5f6110ef82612175565b610aef825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460a01c60011490565b6111346121b2565b5f8081828347335af1610b10573d81823e3d81fd5b611154838383610f4b565b813b156110935761109383838360405180602001604052805f8152506121e7565b6060611181838361226c565b9392505050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b60606111cd848461228d565b5f6111da3386868661189f565b90506111e581611d36565b6111ef8585612352565b95945050505050565b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015473ffffffffffffffffffffffffffffffffffffffff16806112515763ceea21b65f526004601cfd5b919050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000005ea00ac477b1030ce78506496e8c2de24bf516146112c5576040517fa8eb05d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280546fffffffffffffffffffffffffffffffff80821670010000000000000000000000000000000092839004821685019182169283021790925561130e908490849061244b565b50505050565b61131c6121b2565b6040805160c0810182526611c37937e08000815265ffffffffffff7f00000000000000000000000000000000000000000000000000000000648b64ef8116602083019081527f00000000000000000000000000000000000000000000000000000000649dd9ef821683850190815261ffff606085018181526103e860808701908152600160a0880190815297517f01308e65000000000000000000000000000000000000000000000000000000008152965169ffffffffffffffffffff166004880152935185166024870152915190931660448501525182166064840152511660848201529051151560a48201527f00000000000000000000000000005ea00ac477b1030ce78506496e8c2de24bf59073ffffffffffffffffffffffffffffffffffffffff8216906301308e659060c4015f604051808303815f87803b158015611464575f80fd5b505af1158015611476573d5f803e3d5ffd5b50506040517f12738db800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007ade04fa0cbe2167e8bff758f48879bd0c6fff9281166004830152841692506312738db891506024015f604051808303815f87803b158015611500575f80fd5b505af1158015611512573d5f803e3d5ffd5b50506040517f8e7d1e4300000000000000000000000000000000000000000000000000000000815271a26b00c1f0df003000390027140000faa71960048201526001602482015273ffffffffffffffffffffffffffffffffffffffff84169250638e7d1e4391506044015f604051808303815f87803b158015611593575f80fd5b505af11580156115a5573d5f803e3d5ffd5b50506040517f7f2a5cca00000000000000000000000000000000000000000000000000000000815273f408bee3443d0397e2c1cde588fb060ac657006f60048201526001602482015273ffffffffffffffffffffffffffffffffffffffff84169250637f2a5cca91506044015f604051808303815f87803b158015611628575f80fd5b505af115801561163a573d5f803e3d5ffd5b50506040517f7f2a5cca00000000000000000000000000000000000000000000000000000000815273e3d3d0ed702504e19825f44bc6542ff2ec45cb9a60048201526001602482015273ffffffffffffffffffffffffffffffffffffffff84169250637f2a5cca91506044015f604051808303815f87803b1580156116bd575f80fd5b505af11580156116cf573d5f803e3d5ffd5b5050505050565b5f816116e957638f4eb6045f526004601cfd5b7f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52815f5263ffffffff601c600c2054169050919050565b61172b6121b2565b6117345f6124de565b565b600280546fffffffffffffffffffffffffffffffff808216600101167fffffffffffffffffffffffffffffffff0000000000000000000000000000000090911617905580156117f2576117bc825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460a01c60011490565b6117f2576040517f532201f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bdc3383612543565b6060610aef338361226c565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b61186c6611c37937e0800082611bab565b5f5b818110156110935761189783838381811061188b5761188b613718565b90506020020135611be6565b60010161186e565b5f6040518360051b8086833781205f969096526020959095525060409081526060600c209390525090919050565b6118d76001611f7a565b50610bdc828261264a565b6118ed858585610f4b565b833b156116cf576116cf85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506121e792505050565b606061194765e35fa931a00083611bab565b335f8367ffffffffffffffff81111561196257611962613745565b60405190808252806020026020018201604052801561198b578160200160208202803683370190505b5090505f5b848110156119e3576119ba8686838181106119ad576119ad613718565b9050602002013584612142565b8282815181106119cc576119cc613718565b602090810291909101015260019283019201611990565b50949350505050565b60606119f782612175565b611a08611a03836126f1565b6128a2565b604051602001611a189190613772565b6040516020818303038152906040529050919050565b611a3f65e35fa931a0006001611bab565b6110938383836128af565b611a5c6612a6d8e11220006001611bab565b611a678383836128af565b5f828152600160208181526040832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790557f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5290912083018301805460a081811c90931890921b9091189055505050565b6060611aed611a036128cb565b604051602001611afd9190613772565b604051602081830303815290604052905090565b6060611b27868686866612a6d8e1122000611c99565b5f611b343386868661189f565b9050611b3f81611d36565b610b4c878787876128eb565b611b536121b2565b63389a75e1600c52805f526020600c208054421115611b7957636f5e88185f526004601cfd5b5f9055610b10816124de565b611b8d6121b2565b8060601b611ba257637448fbae5f526004601cfd5b610b10816124de565b8082023414610bdc576040517f3c6b4b2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bef81612a6a565b5f818152600160208181526040832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790557f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5290912082018201805460a081811c90931890921b90911890556040518181527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a150565b838214611cd2576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000005841115611d2c576040517f7a7e96df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116cf8482611bab565b335f90815260208181526040808320848452909152902054428190037f00000000000000000000000000000000000000000000000000000000000151807f0000000000000000000000000000000000000000000000000000000000000030818311818410178015610f43576331e63ea05f52846020526024601cfd5b60605f8467ffffffffffffffff811115611dce57611dce613745565b604051908082528060200260200182016040528015611df7578160200160208202803683370190505b5090505f805b86811015611e7757611e3f888883818110611e1a57611e1a613718565b90506020020135878784818110611e3357611e33613718565b90506020020135612b39565b15611e6f576001838281518110611e5857611e58613718565b911515602092830291909101909101526001909101905b600101611dfd565b50805f03611eb1576040517fc17b61ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ec165e35fa931a00082612b6a565b5095945050505050565b5f1960601c82811692508381169350815f52837f7d8825530a5a2e7a00000000000000000000000000000000000000000000000017601c5260205f208201820180548216915081611f235763ceea21b65f526004601cfd5b818514851517611f4757815f526030600c2054611f4757634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a450505050565b5f7f00000000000000000000000000000000000000000000000000000000649dd9ef421115611fd5576040517f589ed34b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fe66611c37937e0800083611bab565b50600280546fffffffffffffffffffffffffffffffff70010000000000000000000000000000000080830482169094018116938402911617905590565b5f818152446020526040600c2062ffffff165b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015415610aef5760010162ffffff16612036565b73ffffffffffffffffffffffffffffffffffffffff90911690816120a45763ea553b345f526004601cfd5b805f527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260205f208101810180548060601b156120eb5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff8116612115576301336cea5f526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a45050565b5f61214c83612a6a565b6121558361216b565b5f61215f83612023565b90506111813382612079565b610b105f82612543565b62ffffff811115610b10576040517fcbbc48a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314611734576382b429005f526004601cfd5b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a0840152801561222e578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1612253573d1561224f573d5f803e3d5ffd5b5f83525b508060e01b825114610f435763d1a57ed65f526004601cfd5b60605f61227883611f7a565b905061228584848361244b565b949350505050565b7f00000000000000000000000000000000000000000000000000000000649dd9ef4211156122e7576040517f589ed34b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000005811115612341576040517f7a7e96df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bdc816611c37937e08000611bab565b60605f8267ffffffffffffffff81111561236e5761236e613745565b604051908082528060200260200182016040528015612397578160200160208202803683370190505b5090505f805b848110156123fe576123c68686838181106123ba576123ba613718565b90506020020135612b81565b156123f65760018382815181106123df576123df613718565b911515602092830291909101909101526001909101905b60010161239d565b50805f03612438576040517fc17b61ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61244181612bda565b5090949350505050565b60605f8367ffffffffffffffff81111561246757612467613745565b604051908082528060200260200182016040528015612490578160200160208202803683370190505b5090505f5b848110156119e3575f6124a785612023565b90506124b38782612079565b808383815181106124c6576124c6613718565b60209081029190910101525060019384019301612495565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f61254d826111f8565b9050505f81815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c5260209091208201820180549193821691826125b45763ceea21b65f526004601cfd5b825f528160010154808614848714178615176125e1576030600c20546125e157634b6e7f185f526004601cfd5b80156125ee575f83600101555b5082189055601c600c2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055815f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4505050565b3360181b62ffffff8316175f526020819052604060092061266a83612175565b61267381611d36565b6126b0835f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460a01c60011490565b156126e7576040517f475a253500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110933384612079565b606061273a6040518060400160405280600481526020017f6e616d650000000000000000000000000000000000000000000000000000000081525061273584612c2d565b612c4a565b6127ae6040518060400160405280600d81526020017f65787465726e616c5f6c696e6b000000000000000000000000000000000000008152506040518060400160405280601281526020017f68747470733a2f2f787879797a7a2e6172740000000000000000000000000000815250612c4a565b6128056040518060400160405280600b81526020017f6465736372697074696f6e0000000000000000000000000000000000000000008152506040518060a0016040528060648152602001613d4760649139612c4a565b6128476040518060400160405280600581526020017f696d61676500000000000000000000000000000000000000000000000000000081525061273587612c76565b61288e6040518060400160405280600a81526020017f617474726962757465730000000000000000000000000000000000000000000081525061288988612c94565b612e99565b604051602001611a189594939291906137b6565b6060610aef825f80612eae565b6128b883612a6a565b6128c18361216b565b611093828261264a565b60606040518060a00160405280607a8152602001613dab607a9139905090565b60605f8467ffffffffffffffff81111561290757612907613745565b604051908082528060200260200182016040528015612930578160200160208202803683370190505b5090505f805b86811015612a1f57612953888883818110611e1a57611e1a613718565b15612a17576129ec86868381811061296d5761296d613718565b602090810292909201355f81815260018085526040822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790557f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52939020810101805460a081811c90941890931b90921890915550565b6001838281518110612a0057612a00613718565b911515602092830291909101909101526001909101905b600101612936565b50805f03612a59576040517fc17b61ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ec16612a6d8e112200082612b6a565b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c526020902081018101548073ffffffffffffffffffffffffffffffffffffffff811115612aea576040517f475a253500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314611093576040517fcdf1f8f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612b4383612a6a565b612b4c82612b81565b15612b6257612b5a8361216b565b506001610aef565b505f92915050565b818102348181039114611093576110933382612fae565b5f612b8b82612175565b5f8281527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020820182015415612bc857505f919050565b612bd23383612079565b506001919050565b6002805463ffffffff6fffffffffffffffffffffffffffffffff70010000000000000000000000000000000080840482168601928316029216919091179091555f90610aef6611c37937e0800084612b6a565b6060612c3a826003612fc7565b604051602001611a1891906138bc565b60608282604051602001612c5f929190613900565b604051602081830303815290604052905092915050565b6060612c84611a038361306b565b604051602001611a189190613989565b60605f612cde6040518060400160405280600581526020017f436f6c6f72000000000000000000000000000000000000000000000000000000815250612cd985612c2d565b613088565b9050612ce9836110e5565b15612dfc575f612d636040518060400160405280600981526020017f46696e616c697a656400000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f5965730000000000000000000000000000000000000000000000000000000000815250613088565b604080518082018252600981527f46696e616c697a657200000000000000000000000000000000000000000000006020808301919091525f8881526001909152919091205491925083918391612dd291612cd99073ffffffffffffffffffffffffffffffffffffffff1661309d565b604051602001612de4939291906139cd565b60405160208183030381529060405292505050919050565b80612e716040518060400160405280600981526020017f46696e616c697a656400000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f4e6f000000000000000000000000000000000000000000000000000000000000815250613088565b604051602001612e82929190613a95565b604051602081830303815290604052915050919050565b60608282604051602001612c5f929190613b3f565b606083518015612fa6576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c16515f53603f81600c1c1651600153603f8160061c1651600253603f811651600353505f518252600482019150808210612f1e576020016040527f3d3d00000000000000000000000000000000000000000000000000000000000060038406600204808303919091525f8615159091029182900352900382525b509392505050565b5f805f8084865af1610bdc5763b12d13eb5f526004601cfd5b6060601f1960428360011b0116604051019050602081016040525f8152806f30313233343536373839616263646566600f528283018203600119855b600f811651948201946001860153600f8160041c1651855360081c84830361300357801561303857632194895a5f526004601cfd5b5050508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910190815292915050565b6060613078826003612fc7565b604051602001611a189190613bbf565b60608282604051602001612c5f929190613c9c565b60606130a8826130df565b805161307882526002017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe90910190815292915050565b60606040519050608081016040526f30313233343536373839616263646566600f5260028101905060288152602081015f60288201528260601b92505f5b808101820184821a600f81165160018301538060041c518253505060018101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed0161311d575050919050565b5f6020828403121561317a575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611181575f80fd5b5f602082840312156131b9575f80fd5b5035919050565b5f8083601f8401126131d0575f80fd5b50813567ffffffffffffffff8111156131e7575f80fd5b6020830191508360208260051b8501011115613201575f80fd5b9250929050565b5f805f805f6060868803121561321c575f80fd5b853567ffffffffffffffff80821115613233575f80fd5b61323f89838a016131c0565b90975095506020880135915080821115613257575f80fd5b50613264888289016131c0565b96999598509660400135949350505050565b602080825282518282018190525f9190848201906040850190845b818110156132af578351151583529284019291840191600101613291565b50909695505050505050565b5f5b838110156132d55781810151838201526020016132bd565b50505f910152565b602081525f82518060208401526132fb8160408501602087016132bb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611251575f80fd5b5f8060408385031215613361575f80fd5b61336a8361332d565b946020939093013593505050565b80358015158114611251575f80fd5b5f805f60408486031215613399575f80fd5b833567ffffffffffffffff8111156133af575f80fd5b6133bb868287016131c0565b90945092506133ce905060208501613378565b90509250925092565b5f805f606084860312156133e9575f80fd5b6133f28461332d565b92506134006020850161332d565b9150604084013590509250925092565b5f805f60608486031215613422575f80fd5b61342b8461332d565b95602085013595506040909401359392505050565b602080825282518282018190525f9190848201906040850190845b818110156132af5783518352928401929184019160010161345b565b5f805f60408486031215613489575f80fd5b833567ffffffffffffffff81111561349f575f80fd5b6134ab868287016131c0565b909790965060209590950135949350505050565b5f602082840312156134cf575f80fd5b6111818261332d565b5f80604083850312156134e9575f80fd5b823591506134f960208401613378565b90509250929050565b5f8060408385031215613513575f80fd5b61351c8361332d565b91506134f960208401613378565b5f806020838503121561353b575f80fd5b823567ffffffffffffffff811115613551575f80fd5b61355d858286016131c0565b90969095509350505050565b5f805f806060858703121561357c575f80fd5b6135858561332d565b9350602085013567ffffffffffffffff8111156135a0575f80fd5b6135ac878288016131c0565b9598909750949560400135949350505050565b5f80604083850312156135d0575f80fd5b50508035926020909101359150565b5f805f805f608086880312156135f3575f80fd5b6135fc8661332d565b945061360a6020870161332d565b935060408601359250606086013567ffffffffffffffff8082111561362d575f80fd5b818801915088601f830112613640575f80fd5b81358181111561364e575f80fd5b89602082850101111561365f575f80fd5b9699959850939650602001949392505050565b5f805f60608486031215613684575f80fd5b505081359360208301359350604090920135919050565b5f80604083850312156136ac575f80fd5b6136b58361332d565b91506134f96020840161332d565b6fffffffffffffffffffffffffffffffff828116828216039080821115613711577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081525f82516137a981601d8501602087016132bb565b91909101601d0192915050565b7f7b0000000000000000000000000000000000000000000000000000000000000081525f86516137ed816001850160208b016132bb565b80830190507f2c00000000000000000000000000000000000000000000000000000000000000806001830152875161382c816002850160208c016132bb565b600292019182018190528651613849816003850160208b016132bb565b600392019182018190528551613866816004850160208a016132bb565b600492019182015283516138818160058401602088016132bb565b016138ae600582017f7d000000000000000000000000000000000000000000000000000000000000009052565b600601979650505050505050565b7f230000000000000000000000000000000000000000000000000000000000000081525f82516138f38160018501602087016132bb565b9190910160010192915050565b5f7f220000000000000000000000000000000000000000000000000000000000000080835284516139388160018601602089016132bb565b7f223a22000000000000000000000000000000000000000000000000000000000060019185019182015284516139758160048401602089016132bb565b016004810191909152600501949350505050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000081525f82516139c081601a8501602087016132bb565b91909101601a0192915050565b7f5b0000000000000000000000000000000000000000000000000000000000000081525f8451613a048160018501602089016132bb565b80830190507f2c000000000000000000000000000000000000000000000000000000000000008060018301528551613a43816002850160208a016132bb565b60029201918201528351613a5e8160038401602088016132bb565b7f5d000000000000000000000000000000000000000000000000000000000000006003929091019182015260040195945050505050565b7f5b0000000000000000000000000000000000000000000000000000000000000081525f8351613acc8160018501602088016132bb565b7f2c000000000000000000000000000000000000000000000000000000000000006001918401918201528351613b098160028401602088016132bb565b7f5d0000000000000000000000000000000000000000000000000000000000000060029290910191820152600301949350505050565b7f220000000000000000000000000000000000000000000000000000000000000081525f8351613b768160018501602088016132bb565b7f223a0000000000000000000000000000000000000000000000000000000000006001918401918201528351613bb38160038401602088016132bb565b01600301949350505050565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222077696474683d2236393022206865696768743d223639302260208201527f3e3c726563742077696474683d2236393022206865696768743d22363930222060408201527f66696c6c3d22230000000000000000000000000000000000000000000000000060608201525f8251613c688160678501602087016132bb565b7f22202f3e3c2f7376673e000000000000000000000000000000000000000000006067939091019283015250607101919050565b7f7b2274726169745f74797065223a22000000000000000000000000000000000081525f8351613cd381600f8501602088016132bb565b7f222c2276616c7565223a22000000000000000000000000000000000000000000600f918401918201528351613d1081601a8401602088016132bb565b7f227d000000000000000000000000000000000000000000000000000000000000601a9290910191820152601c0194935050505056fe50726f6f66206f6620636f6c6f722e20585859595a5a206973206120636f6c6c656374696f6e206f662066756c6c79206f6e636861696e2c20756e697175652c20636f6d706f7361626c652c20616e6420636f6c6c65637461626c6520636f6c6f72732e7b226e616d65223a22585859595a5a222c226465736372697074696f6e223a22436f6c6c65637469626c652c20636f6d706f7361626c652c20616e6420756e69717565206f6e636861696e20636f6c6f72732e222c2265787465726e616c5f6c696e6b223a2268747470733a2f2f787879797a7a2e617274227d

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

0000000000000000000000007039813983ba47a5a46b19f3a269aef5c6c75abf0000000000000000000000007ade04fa0cbe2167e8bff758f48879bd0c6fff92000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000005ea00ac477b1030ce78506496e8c2de24bf5000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000006969690000000000000000000000000000000000000000000000000000000000ff6000000000000000000000000000000000000000000000000000000000000000ff00

-----Decoded View---------------
Arg [0] : initialOwner (address): 0x7039813983ba47a5A46B19f3a269aeF5C6c75ABF
Arg [1] : creatorPayout (address): 0x7ade04fa0cbE2167E8bff758F48879BD0C6fFf92
Arg [2] : maxBatchSize (uint256): 5
Arg [3] : preMintIds (uint24[]): 0,16777215,6908265,16736256,65280
Arg [4] : seaDrop (address): 0x00005EA00Ac477B1030CE78506496e8C2dE24bf5

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000007039813983ba47a5a46b19f3a269aef5c6c75abf
Arg [1] : 0000000000000000000000007ade04fa0cbe2167e8bff758f48879bd0c6fff92
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [4] : 00000000000000000000000000005ea00ac477b1030ce78506496e8c2de24bf5
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000ffffff
Arg [8] : 0000000000000000000000000000000000000000000000000000000000696969
Arg [9] : 0000000000000000000000000000000000000000000000000000000000ff6000
Arg [10] : 000000000000000000000000000000000000000000000000000000000000ff00


Deployed Bytecode Sourcemap

1714:937:6:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2419:230;;;;;;;;;;-1:-1:-1;2419:230:6;;;;;:::i;:::-;;:::i;:::-;;;516:14:16;;509:22;491:41;;479:2;464:18;2419:230:6;;;;;;;;6218:120:11;;;;;;:::i;:::-;;:::i;:::-;;3659:435;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;3505:328:8:-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;7313:541:2:-;;;;;;;;;;-1:-1:-1;7313:541:2;;;;;:::i;:::-;;:::i;:::-;;;3484:42:16;3472:55;;;3454:74;;3442:2;3427:18;7313:541:2;3308:226:16;8147:119:2;;;;;;:::i;:::-;;:::i;1261:48:8:-;;;;;;;;;;;;;;;;;;4145:25:16;;;4133:2;4118:18;1261:48:8;3999:177:16;215:44:14;;;;;;;;;;;;;;;3355:87:8;;;;;;;;;;-1:-1:-1;3425:10:8;;;;3355:87;;265:41:14;;;;;;;;;;;;;;;905:314:10;;;:::i;3018:100:8:-;;;;;;;;;;;;;:::i;914:367:11:-;;;;;;:::i;:::-;;:::i;1237:1691:7:-;;;;;;;;;;-1:-1:-1;1237:1691:7;;;;;:::i;:::-;;:::i;9956:2995:2:-;;;;;;:::i;:::-;;:::i;6825:616:1:-;;;:::i;5718:485:8:-;;;;;;;;;;-1:-1:-1;5718:485:8;;;;;:::i;:::-;5994:2;5990:15;;;;6015:10;6007:19;;;;5987:40;5832:23;5977:51;6048:4;6041:18;6182:4;6176;6166:21;;5718:485;4597:125;;;;;;;;;;-1:-1:-1;4597:125:8;;;;;:::i;:::-;;:::i;2504:358::-;;;;;;;;;;;;;:::i;13022:198:2:-;;;;;;:::i;:::-;;:::i;1529:138:10:-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1190:65:8:-;;;;;;;;;;;;1242:13;1190:65;;7523:456:1;;;:::i;3206:345:10:-;;;;;;:::i;:::-;;:::i;6170:332:2:-;;;;;;;;;;-1:-1:-1;6170:332:2;;;;;:::i;:::-;;:::i;2178:510:12:-;;;;;;;;;;-1:-1:-1;2178:510:12;;;;;:::i;:::-;;:::i;1436:736::-;;;;;;;;;;;;;:::i;6646:533:2:-;;;;;;;;;;-1:-1:-1;6646:533:2;;;;;:::i;:::-;;:::i;530:49:10:-;;;;;;;;;;;;;;;6563:100:1;;;:::i;1632:63:8:-;;;;;;;;;;-1:-1:-1;1632:63:8;;;;;:::i;:::-;;;;;;;;;;;;;;;;3359:130:12;;;;;;;;;;-1:-1:-1;3359:130:12;;;;;:::i;:::-;-1:-1:-1;3461:10:12;;3413:7;;3461:10;;;;;;;3473:8;;3359:130;;;;;7238:25:16;;;7294:2;7279:18;;7272:34;;;;7322:18;;;7315:34;7226:2;7211:18;3359:130:12;7036:319:16;553:92:14;;;;;;;;;;-1:-1:-1;553:92:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;9211:191:1;;;;;;;;;;-1:-1:-1;9365:20:1;9359:27;9211:191;;1074:52:8;;;;;;;;;;;;1113:13;1074:52;;522:380:7;;;;;;;;;;-1:-1:-1;522:380:7;;;;;:::i;:::-;;:::i;1391:132:10:-;;;;;;:::i;:::-;;:::i;8888:713:2:-;;;;;;;;;;-1:-1:-1;8888:713:2;;;;;:::i;:::-;;:::i;6681:266:11:-;;;;;;:::i;:::-;;:::i;6913:1312:8:-;;;;;;;;;;-1:-1:-1;6913:1312:8;;;;;:::i;:::-;;:::i;2598:147:10:-;;;;;;:::i;:::-;;:::i;13723:249:2:-;;;;;;:::i;:::-;;:::i;1510:668:11:-;;;;;;:::i;:::-;;:::i;1020:48:8:-;;;;;;;;;;;;1057:11;1020:48;;666:210:9;;;;;;;;;;-1:-1:-1;666:210:9;;;;;:::i;:::-;;:::i;2764:186:11:-;;;;;;:::i;:::-;;:::i;3193:87:8:-;;;;;;;;;;-1:-1:-1;3263:10:8;;;;;;;3193:87;;3554:85:12;;;;;;;;;;-1:-1:-1;3624:8:12;3554:85;;10031:107:1;;;;;;;;;;-1:-1:-1;10031:107:1;;10122:9;10688:50:16;;10676:2;10661:18;10031:107:1;10544:200:16;4709:321:11;;;;;;:::i;:::-;;:::i;947:167:9:-;;;;;;;;;;;;;:::i;8357:392:2:-;;;;;;;;;;-1:-1:-1;8357:392:2;;;;;:::i;:::-;8577:4;8570:22;8618:31;8612:4;8605:45;8477:11;8663:19;8727:4;8721;8711:21;8705:28;;8357:392;5434:469:11;;;;;;:::i;:::-;;:::i;8166:708:1:-;;;;;;:::i;:::-;;:::i;940:113:14:-;;;;;;;;;;-1:-1:-1;940:113:14;;;;;:::i;:::-;1005:10;993:11;:23;;;;;;;;;;;:35;;;;;;;1031:15;993:53;;940:113;6149:349:1;;;;;;:::i;:::-;;:::i;9505:435::-;;;;;;;;;;-1:-1:-1;9505:435:1;;;;;:::i;:::-;9775:19;9769:4;9762:33;;;9624:14;9808:26;;;;9918:4;9902:21;;9896:28;;9505:435;2419:230:6;2571:4;2598:44;2630:11;3128:10:12;2930:3;2926:21;;;;3122:17;;;3147:10;3141:17;;3119:40;3167:10;3161:17;;3116:63;3187:10;3181:17;;3113:86;3227:32;3221:39;;;3089:189;;2786:508;2598:44:6;2591:51;2419:230;-1:-1:-1;;2419:230:6:o;6218:120:11:-;6273:35;1173:11:8;6306:1:11;6273:16;:35::i;:::-;6318:13;6328:2;6318:9;:13::i;:::-;6218:120;:::o;3659:435::-;3804:13;3833:60;3864:6;;3872;;1113:13:8;3833:30:11;:60::i;:::-;3903:26;3932:48;3955:10;3967:6;;3975:4;3932:22;:48::i;:::-;3903:77;;3990:42;4013:18;3990:22;:42::i;:::-;4050:37;4072:6;;4080;;4050:21;:37::i;:::-;4043:44;3659:435;-1:-1:-1;;;;;;;3659:435:11:o;3505:328:8:-;3551:13;3738:4;;3725:18;3769:16;3763:4;3756:30;3812:4;3738;3799:18;7313:541:2;7375:14;7467:16;;;7509:24;7503:4;7496:38;7600:4;7584:21;;7576:30;;7568:39;;7646:20;;7630:38;;7620:167;;7701:10;7695:4;7688:24;7768:4;7762;7755:18;7620:167;7820:1;7816:21;7810:28;;7313:541;-1:-1:-1;;7313:541:2:o;8147:119::-;8226:33;8235:10;8247:7;8256:2;8226:8;:33::i;:::-;8147:119;;:::o;905:314:10:-;945:7;964:17;984:34;1016:1;984:31;:34::i;:::-;964:54;;1106:15;1124:28;1142:9;1124:17;:28::i;:::-;1106:46;;1162:26;1168:10;1180:7;1162:5;:26::i;3018:100:8:-;3101:10;;3062:7;;3088:23;;3101:10;;;;;3088;;;;:23;:::i;:::-;3081:30;;;;3018:100;:::o;914:367:11:-;969:7;988:33;1113:13:8;1019:1:11;988:16;:33::i;:::-;1231:43;1247:5;1262:10;1231:15;:43::i;1237:1691:7:-;1335:1;1321:15;;;1317:68;;1359:15;;;;;;;;;;;;;;1317:68;1394:32;1429:28;1450:3;;1454:1;1450:6;;;;;;;:::i;:::-;;;;;;;13924:14:8;14090:16;;;14132:24;14126:4;14119:38;14218:4;14202:21;;14194:30;;14186:39;14180:46;;13859:383;1429:28:7;1394:63;-1:-1:-1;1394:63:7;1547:148;;;;1611:17;1584:44;;1580:105;;;1655:15;;;;;;;;;;;;;;1580:105;1776:31;;;1797:10;1776:31;1772:185;;1828:47;1845:17;1864:10;8577:4:2;8570:22;8618:31;8612:4;8605:45;8477:11;8663:19;8727:4;8721;8711:21;8705:28;;8357:392;1828:47:7;1823:124;;1902:30;;;;;;;;;;;;;;1823:124;2072:10;:32;;;;;;;;;;;;;;;;;;2124:13;2093:3;;2072:10;2130:6;;;;;:::i;:::-;;;;;;;2124:5;:13::i;:::-;2164:1;2147:775;2167:14;;;2147:775;;;2198:10;2211:3;;2215:1;2211:6;;;;;;;:::i;:::-;;;;;;;2198:19;;2258:24;2279:2;13924:14:8;14090:16;;;14132:24;14126:4;14119:38;14218:4;14202:21;;14194:30;;14186:39;14180:46;;13859:383;2258:24:7;2231:51;-1:-1:-1;2231:51:7;2440:26;;;;;;;;2436:87;;2493:15;;;;;;;;;;;;;;2436:87;2540:13;2536:164;;;2604:17;2577:44;;2573:113;;;2652:15;;;;;;;;;;;;;;2573:113;2843:9;2849:2;2843:5;:9::i;:::-;-1:-1:-1;;2894:3:7;;2147:775;;;;1307:1621;;1237:1691;;;:::o;9956:2995:2:-;10233:1;10377:16;;;10422:24;10448:8;10419:38;10413:4;10406:52;10524:4;10508:21;;10500:30;;10492:39;;10567:20;;10221:15;10257:25;;;;10301:23;;;;10613:36;;;10492:39;10752:15;;;10741:27;;10731:328;;10798:5;10788:146;;10840:10;10834:4;10827:24;10911:4;10905;10898:18;10788:146;10964:10;10958:4;10951:24;11040:4;11034;11027:18;10731:328;11133:2;11123:135;;11168:10;11162:4;11155:24;11239:4;11233;11226:18;11123:135;11361:4;11355;11348:18;11419:13;11416:1;11412:21;11406:28;11383:51;;11569:15;11559:8;11556:29;11549:4;11539:8;11536:18;11533:53;11523:288;;11642:4;11636;11626:21;11620:28;11610:183;;11689:10;11683:4;11676:24;11766:4;11760;11753:18;11610:183;11886:15;11883:55;;;11934:1;11918:13;11915:1;11911:21;11904:32;11883:55;12050:13;;;12029:35;12007:58;;-1:-1:-1;12183:4:2;12177;12167:21;;;12233:22;;12229:30;;12205:55;;-1:-1:-1;12351:16:2;;;12405:21;12474:20;;12257:1;12470:28;12550:20;12525:46;;12515:192;;12608:10;12602:4;12595:24;12684:4;12678;12671:18;12515:192;12724:42;;12889:2;12885;12879:4;12852:25;12846:4;;12835:57;12911:33;9956:2995;;;:::o;6825:616:1:-;6918:15;10122:9;6936:45;;:15;:45;6918:63;;7149:19;7143:4;7136:33;7199:8;7193:4;7186:22;7255:7;7248:4;7242;7232:21;7225:38;7402:8;7355:45;7352:1;7349;7344:67;7051:374;6825:616::o;4597:125:8:-;4651:4;4667:15;4679:2;4667:11;:15::i;:::-;4699:16;4712:2;13302:4;17500:16:2;;;17542:24;17536:4;17529:38;17637:4;17621:21;;17613:30;;17605:39;17599:46;17594:3;17590:56;1434:1:8;13325:30;;13245:117;2504:358;10527:13:1;:11;:13::i;:::-;2648:1:8::1;;;;;2624:13;2614:8;2607:5;2602:48;2716:130;;2771:16;2648:1;;2750:38;2815:16;2648:1;2805:27;13022:198:2::0;13119:26;13132:4;13138:2;13142;13119:12;:26::i;:::-;35982:14;;13155:58;;;13173:40;13196:4;13202:2;13206;13173:40;;;;;;;;;;;;:22;:40::i;1529:138:10:-;1599:16;1634:26;1647:2;1651:8;1634:12;:26::i;:::-;1627:33;1529:138;-1:-1:-1;;;1529:138:10:o;7523:456:1:-;7725:19;7719:4;7712:33;7771:8;7765:4;7758:22;7823:1;7816:4;7810;7800:21;7793:32;7954:8;7908:44;7905:1;7902;7897:66;7523:456::o;3206:345:10:-;3295:13;3320:35;3351:3;;3320:30;:35::i;:::-;3365:26;3394:45;3417:10;3429:3;;3434:4;3394:22;:45::i;:::-;3365:74;;3449:42;3472:18;3449:22;:42::i;:::-;3508:36;3540:3;;3508:31;:36::i;:::-;3501:43;3206:345;-1:-1:-1;;;;;3206:345:10:o;6170:332:2:-;6228:14;15491:16;;;15533:24;15527:4;15520:38;15635:4;15619:21;;15611:30;;15603:39;;15597:46;15581:64;;;6351:135;;6400:10;6394:4;6387:24;6467:4;6461;6454:18;6351:135;6170:332;;;:::o;2178:510:12:-;2259:10;:21;2273:7;2259:21;;2255:72;;2303:13;;;;;;;;;;;;;;2255:72;2560:10;;;;2610:22;;;2560:10;;;;;;;:30;;2610:22;;;;;;;;;;2642:39;;2650:9;;2560:30;;2642:7;:39::i;:::-;;2245:443;2178:510;;:::o;1436:736::-;10527:13:1;:11;:13::i;:::-;1577:326:12::1;::::0;;::::1;::::0;::::1;::::0;;1624:11:::1;1577:326:::0;;::::1;1672:13;1577:326:::0;::::1;;::::0;::::1;::::0;;;1720:24:::1;1577:326:::0;::::1;::::0;;;;;;1789:16:::1;1577:326:::0;;;;;;1838:4:::1;1577:326:::0;;;;;;1884:4:::1;1577:326:::0;;;;;;1539:374;;;;;11972:13:16;;11987:22;11968:42;1539:374:12::1;::::0;::::1;11950:61:16::0;12040:24;;12135:21;;12113:20;;;12106:51;12199:24;;12195:33;;;12173:20;;;12166:63;12260:24;12347:23;;12325:20;;;12318:53;12413:24;12409:33;12387:20;;;12380:63;12495:24;;12488:32;12481:40;12459:20;;;12452:70;1521:7:12::1;::::0;1539:24:::1;::::0;::::1;::::0;::::1;::::0;11922:19:16;;1539:374:12::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;1923:50:12::1;::::0;;;;:34:::1;1958:14;3472:55:16::0;;1923:50:12::1;::::0;::::1;3454:74:16::0;1923:34:12;::::1;::::0;-1:-1:-1;1923:34:12::1;::::0;-1:-1:-1;3427:18:16;;1923:50:12::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;1983:62:12::1;::::0;;;;542:42:::1;1983:62;::::0;::::1;12701:74:16::0;2040:4:12::1;12791:18:16::0;;;12784:50;1983:33:12::1;::::0;::::1;::::0;-1:-1:-1;1983:33:12::1;::::0;-1:-1:-1;12674:18:16;;1983:62:12::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;2055:50:12::1;::::0;;;;641:42:::1;2055:50;::::0;::::1;12701:74:16::0;2100:4:12::1;12791:18:16::0;;;12784:50;2055:19:12::1;::::0;::::1;::::0;-1:-1:-1;2055:19:12::1;::::0;-1:-1:-1;12674:18:16;;2055:50:12::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;2115:50:12::1;::::0;;;;740:42:::1;2115:50;::::0;::::1;12701:74:16::0;2160:4:12::1;12791:18:16::0;;;12784:50;2115:19:12::1;::::0;::::1;::::0;-1:-1:-1;2115:19:12::1;::::0;-1:-1:-1;12674:18:16;;2115:50:12::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;1483:689;1436:736::o:0;6646:533:2:-;6709:14;6869:5;6859:143;;6907:10;6901:4;6894:24;6983:4;6977;6970:18;6859:143;7028:24;7022:4;7015:38;7079:5;7073:4;7066:19;7142:20;7134:4;7128;7118:21;7112:28;7108:55;7098:65;;6646:533;;;:::o;6563:100:1:-;10527:13;:11;:13::i;:::-;6635:21:::1;6653:1;6635:9;:21::i;:::-;6563:100::o:0;522:380:7:-;701:10;:15;;;;;;715:1;701:15;;;;;;;;;736:125;;;;774:20;787:6;13302:4:8;17500:16:2;;;17542:24;17536:4;17529:38;17637:4;17621:21;;17613:30;;17605:39;17599:46;17594:3;17590:56;1434:1:8;13325:30;;13245:117;774:20:7;769:82;;821:15;;;;;;;;;;;;;;769:82;870:25;876:10;888:6;870:5;:25::i;1391:132:10:-;1447:16;1482:34;1495:10;1507:8;1482:12;:34::i;8888:713:2:-;9103:10;9096:18;9089:26;9075:40;;9212:8;9206:4;9199:22;9247:31;9241:4;9234:45;9305:8;9299:4;9292:22;9357:10;9350:4;9344;9334:21;9327:41;9442:10;9436:4;9429:24;9561:8;9557:2;9553:17;9549:2;9545:26;9535:8;9500:33;9494:4;9488;9466:119;8888:713;;:::o;6681:266:11:-;6753:44;1173:11:8;6786:3:11;6753:16;:44::i;:::-;6812:9;6807:134;6823:14;;;6807:134;;;6854:17;6864:3;;6868:1;6864:6;;;;;;;:::i;:::-;;;;;;;6854:9;:17::i;:::-;6913:3;;6807:134;;6913:1312:8;7044:22;7183:4;7177:11;7296:10;7293:1;7289:18;7422:8;7410:10;7398;7385:46;7531:183;;7784:1;7777:17;;;;7868:4;7861:23;;;;-1:-1:-1;7957:4:8;7950:18;;;8124:4;8118;8108:21;8185:24;;;-1:-1:-1;8108:21:8;;6913:1312;-1:-1:-1;6913:1312:8:o;2598:147:10:-;2671:34;2703:1;2671:31;:34::i;:::-;;2715:23;2729:2;2733:4;2715:13;:23::i;13723:249:2:-;13869:26;13882:4;13888:2;13892;13869:12;:26::i;:::-;35982:14;;13905:60;;;13923:42;13946:4;13952:2;13956;13960:4;;13923:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;13923:22:2;;-1:-1:-1;;;13923:42:2:i;1510:668:11:-;1579:16;1607:42;1113:13:8;1638:3:11;1607:16;:42::i;:::-;1884:10;1853:12;1946:3;1932:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1932:25:11;;1906:51;;1972:9;1967:182;1983:14;;;1967:182;;;2026:29;2042:3;;2046:1;2042:6;;;;;;;:::i;:::-;;;;;;;2050:4;2026:15;:29::i;:::-;2014:6;2021:1;2014:9;;;;;;;;:::i;:::-;;;;;;;;;;:41;2097:3;2118:6;;;;2097:3;1967:182;;;-1:-1:-1;2165:6:11;1510:668;-1:-1:-1;;;;1510:668:11:o;666:210:9:-;734:13;759:15;771:2;759:11;:15::i;:::-;838:30;844:14;855:2;844:10;:14::i;:::-;838:28;:30::i;:::-;791:78;;;;;;;;:::i;:::-;;;;;;;;;;;;;784:85;;666:210;;;:::o;2764:186:11:-;2857:33;1113:13:8;2888:1:11;2857:16;:33::i;:::-;2900:43;2924:5;2931;2938:4;2900:23;:43::i;4709:321::-;4813:46;1242:13:8;4857:1:11;4813:16;:46::i;:::-;4870:43;4894:5;4901;4908:4;4870:23;:43::i;:::-;12084:14;;;;:10;:14;;;;;;;:26;;;;5012:10;12084:26;;;18050:24:2;18044:4;18037:38;18125:21;;;18117:30;;18109:39;;18175:20;;18266:3;18262:16;;;18251:28;;;18242:38;;;18230:51;;;18208:74;;9956:2995;;;:::o;947:167:9:-;991:13;1070:36;1076:20;:18;:20::i;1070:36::-;1023:84;;;;;;;;:::i;:::-;;;;;;;;;;;;;1016:91;;947:167;:::o;5434:469:11:-;5590:13;5619:73;5650:6;;5658;;1242:13:8;5619:30:11;:73::i;:::-;5702:26;5731:48;5754:10;5766:6;;5774:4;5731:22;:48::i;:::-;5702:77;;5789:42;5812:18;5789:22;:42::i;:::-;5848:48;5881:6;;5889;;5848:32;:48::i;8166:708:1:-;10527:13;:11;:13::i;:::-;8400:19:::1;8394:4;8387:33;8446:12;8440:4;8433:26;8508:4;8502;8492:21;8614:12;8608:19;8595:11;8592:36;8589:157;;;8660:10;8654:4;8647:24;8727:4;8721;8714:18;8589:157;8823:1;8802:23:::0;;8844::::1;8854:12:::0;8844:9:::1;:23::i;6149:349::-:0;10527:13;:11;:13::i;:::-;6321:8:::1;6317:2;6313:17;6303:150;;6363:10;6357:4;6350:24;6434:4;6428;6421:18;6303:150;6472:19;6482:8;6472:9;:19::i;12027:345:8:-:0;12289:8;12277:9;:20;12263:9;:35;12259:97;;12325:16;;;;;;;;;;;;;;11485:244:11;11535:38;11570:2;11535:34;:38::i;:::-;12084:14;;;;:10;:14;;;;;;;:26;;;;11632:10;12084:26;;;18050:24:2;18044:4;18037:38;18125:21;;;18117:30;;18109:39;;18175:20;;18266:3;18262:16;;;18251:28;;;18242:38;;;18230:51;;;18208:74;;11704:18:11;;4145:25:16;;;11704:18:11;;4133:2:16;4118:18;11704::11;;;;;;;11485:244;:::o;14979:382:8:-;15130:20;;;15126:79;;15173:21;;;;;;;;;;;;;;15126:79;15229:23;15218:34;;15214:94;;;15275:22;;;;;;;;;;;;;;15214:94;15317:37;15334:1;15344:9;15317:16;:37::i;1249:1134:14:-;1445:10;1404:26;1433:23;;;;;;;;;;;:47;;;;;;;;;1663:15;:36;;;1748:19;1803:16;2115:32;;;2149:29;;;2112:67;2192:175;;;;2241:27;2238:1;2231:38;2299:18;2293:4;2286:32;2348:4;2342;2335:18;7383:831:11;7502:13;7531:22;7567:6;7556:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7556:25:11;;7531:50;;7591:24;7630:9;7625:310;7641:17;;;7625:310;;;7679:48;7706:6;;7713:1;7706:9;;;;;;;:::i;:::-;;;;;;;7717:6;;7724:1;7717:9;;;;;;;:::i;:::-;;;;;;;7679:26;:48::i;:::-;7675:191;;;7761:4;7747:8;7756:1;7747:11;;;;;;;;:::i;:::-;:18;;;:11;;;;;;;;;;;:18;7815;;;;;7675:191;7907:3;;7625:310;;;;8018:16;8038:1;8018:21;8014:74;;8062:15;;;;;;;;;;;;;;8014:74;8131:50;1113:13:8;8164:16:11;8131:18;:50::i;:::-;-1:-1:-1;8199:8:11;7383:831;-1:-1:-1;;;;;7383:831:11:o;26552:1436:2:-;26735:1;26731:6;26727:2;26723:15;26782:7;26766:14;26762:28;26751:39;;26829:2;26813:14;26809:23;26803:29;;26902:2;26896:4;26889:16;26960:2;26934:24;26931:32;26925:4;26918:46;27030:4;27024;27014:21;27010:2;27006:30;27002:2;26998:39;27089:13;27083:20;27067:14;27063:41;27050:54;;27178:5;27168:134;;27216:10;27210:4;27203:24;27283:4;27277;27270:18;27168:134;27485:5;27481:2;27478:13;27473:2;27466:10;27463:29;27453:280;;27525:5;27519:4;27512:19;27580:4;27574;27564:21;27558:28;27548:171;;27623:10;27617:4;27610:24;27696:4;27690;27683:18;27548:171;27827:1;27823:21;27816:38;;;27969:2;27846:7;27953:5;27926:25;27920:4;;27909:63;;26552:1436;;;:::o;6005:602:10:-;6091:7;6132:24;6114:15;:42;6110:92;;;6179:12;;;;;;;;;;;;;;6110:92;6211:47;1057:11:8;6240:17:10;6211:16;:47::i;:::-;-1:-1:-1;6493:10:10;;;;;;;;;;:39;;;6552:22;;;;;;;;;;;6005:602::o;10974:791:8:-;11038:7;11105:15;;;11146:12;11140:4;11133:26;11337:4;11331;11321:21;11344:10;11317:38;11522:213;13924:14;14090:16;;;14132:24;14126:4;14119:38;14218:4;14202:21;;14194:30;;14186:39;;14180:46;11529:34;11522:213;;11695:1;11685:11;1392:8;11684:26;11522:213;;18786:1676:2;19014:20;;;;;;19098:135;;19143:10;19137:4;19130:24;19214:4;19208;19201:18;19098:135;19299:2;19293:4;19286:16;19328:24;19322:4;19315:38;19419:4;19413;19403:21;19399:2;19395:30;19391:2;19387:39;19468:13;19462:20;19557:15;19553:2;19549:24;19546:146;;;19605:10;19599:4;19592:24;19673:4;19667;19660:18;19546:146;19765:23;;19743:46;;19878:4;19871:16;;;19939:4;19933;19923:21;19990:18;;20010:1;19986:26;20062:20;20039:44;;20029:190;;20120:10;20114:4;20107:24;20196:4;20190;20183:18;20029:190;20236:38;;20394:2;20390;20387:1;20360:25;20387:1;;20343:54;8147:119;;:::o;9751:298:11:-;9823:7;9842:41;9877:5;9842:34;:41::i;:::-;9919:12;9925:5;9919;:12::i;:::-;9941:15;9959:23;9977:4;9959:17;:23::i;:::-;9941:41;;9992:26;9998:10;10010:7;9992:5;:26::i;21497:82:2:-;21551:21;21565:1;21569:2;21551:5;:21::i;11830:136:8:-;1392:8;11895:6;:19;11891:69;;;11937:12;;;;;;;;;;;;;;5425:364:1;5637:20;5631:27;5621:8;5618:41;5608:165;;5692:10;5686:4;5679:24;5754:4;5748;5741:18;36203:1405:2;36440:4;36434:11;36490:10;36523:24;36520:1;36513:35;36582:8;36575:4;36572:1;36568:12;36561:30;36690:4;36686:2;36682:13;36678:2;36674:22;36667:4;36664:1;36660:12;36653:44;36731:2;36724:4;36721:1;36717:12;36710:24;36768:4;36761;36758:1;36754:12;36747:26;36801:4;36795:11;36840:1;36833:4;36830:1;36826:12;36819:23;36858:1;36855:71;;;36921:1;36914:4;36911:1;36907:12;36904:1;36897:4;36891;36887:15;36884:1;36877:5;36866:57;36862:62;36855:71;37042:4;37039:1;37032:4;37029:1;37025:12;37018:4;37015:1;37011:12;37008:1;37004:2;36997:5;36992:55;36982:348;;37070:16;37067:220;;;37201:16;37195:4;37189;37174:44;37252:16;37246:4;37239:30;37067:220;37314:1;37311;37304:12;36982:348;;37426:24;37421:3;37417:34;37413:1;37407:8;37404:48;37394:198;;37485:10;37479:4;37472:24;37573:4;37567;37560:18;3818:258:10;3888:16;3959:17;3979:41;4011:8;3979:31;:41::i;:::-;3959:61;;4037:32;4045:2;4049:8;4059:9;4037:7;:32::i;:::-;4030:39;3818:258;-1:-1:-1;;;;3818:258:10:o;7436:341::-;7546:24;7528:15;:42;7524:92;;;7593:12;;;;;;;;;;;;;;7524:92;7642:23;7629:36;;7625:96;;;7688:22;;;;;;;;;;;;;;7625:96;7730:40;7747:3;1057:11:8;7730:16:10;:40::i;4999:658::-;5082:13;5107:20;5141:3;5130:22;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5130:22:10;;5107:45;;5162:22;5199:9;5194:287;5210:14;;;5194:287;;;5245:32;5270:3;;5274:1;5270:6;;;;;;;:::i;:::-;;;;;;;5245:24;:32::i;:::-;5241:171;;;5309:4;5297:6;5304:1;5297:9;;;;;;;;:::i;:::-;:16;;;:9;;;;;;;;;;;:16;5363;;;;;5241:171;5453:3;;5194:287;;;;5494:14;5512:1;5494:19;5490:72;;5536:15;;;;;;;;;;;;;;5490:72;5572:55;5612:14;5572:39;:55::i;:::-;-1:-1:-1;5644:6:10;;4999:658;-1:-1:-1;;;;4999:658:10:o;4288:500::-;4372:16;4400:25;4442:8;4428:23;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4428:23:10;;4400:51;;4466:9;4461:296;4481:8;4477:1;:12;4461:296;;;4545:15;4563:28;4581:9;4563:17;:28::i;:::-;4545:46;;4605:18;4611:2;4615:7;4605:5;:18::i;:::-;4651:7;4637:8;4646:1;4637:11;;;;;;;;:::i;:::-;;;;;;;;;;:21;-1:-1:-1;4700:3:10;4721:11;;;;4700:3;4461:296;;4872:495:1;5019:20;5248:16;;5104:26;;;;;;;5208:38;5205:1;;5197:78;5324:27;4872:495::o;21868:2121:2:-;21934:13;21950:11;21958:2;21950:7;:11::i;:::-;21934:27;;-1:-1:-1;22216:4:2;22209:16;;;22136:20;;;;22254:24;22251:32;;22245:4;22238:46;22350:4;22334:21;;;22326:30;;22318:39;;22393:20;;22136;;22516:33;;;;22613:134;;22661:10;22655:4;22648:24;22728:4;22722;22715:18;22613:134;22841:5;22835:4;22828:19;22900:13;22897:1;22893:21;22887:28;23132:15;23128:2;23125:23;23117:5;23113:2;23110:13;23107:42;23102:2;23095:10;23092:58;23082:293;;23206:4;23200;23190:21;23184:28;23174:183;;23253:10;23247:4;23240:24;23330:4;23324;23317:18;23174:183;23450:15;23447:55;;;23498:1;23482:13;23479:1;23475:21;23468:32;23447:55;-1:-1:-1;23583:27:2;;23561:50;;23726:4;23720;23710:21;23772:18;;23768:26;;23748:47;;23918:2;-1:-1:-1;23604:5:2;23881:25;-1:-1:-1;;23864:57:2;9956:2995;;;:::o;8490:518:8:-;8605:10;5994:2;5990:15;6015:10;6007:19;;5987:40;8558:26;5977:51;6048:4;6041:18;;;6182:4;6176;6166:21;8688:15;6007:19;8688:11;:15::i;:::-;8769:42;8792:18;8769:22;:42::i;:::-;8903:16;8916:2;13302:4;17500:16:2;;;17542:24;17536:4;17529:38;17637:4;17621:21;;17613:30;;17605:39;17599:46;17594:3;17590:56;1434:1:8;13325:30;;13245:117;8903:16;8899:72;;;8942:18;;;;;;;;;;;;;;8899:72;8980:21;8986:10;8998:2;8980:5;:21::i;1165:589:9:-;1228:13;1304:22;;;;;;;;;;;;;;;;;;1316:9;1322:2;1316:5;:9::i;:::-;1304:3;:22::i;:::-;1357:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:3;:42::i;:::-;1430:168;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:3;:168::i;:::-;1629:27;;;;;;;;;;;;;;;;;;1642:13;1652:2;1642:9;:13::i;1629:27::-;1687:33;;;;;;;;;;;;;;;;;;1708:11;1716:2;1708:7;:11::i;:::-;1687:6;:33::i;:::-;1260:487;;;;;;;;;;;;:::i;3416:132:3:-;3474:20;3515:26;3522:4;3528:5;3535;3515:6;:26::i;10380:228:11:-;10476:41;10511:5;10476:34;:41::i;:::-;10553:12;10559:5;10553;:12::i;:::-;10575:26;10589:5;10596:4;10575:13;:26::i;1808:224:9:-;1861:13;1886:139;;;;;;;;;;;;;;;;;;;1808:224;:::o;8611:902:11:-;8741:13;8770:22;8806:6;8795:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;8795:25:11;;8770:50;;8830:24;8869:9;8864:365;8880:17;;;8864:365;;;8918:48;8945:6;;8952:1;8945:9;;;;;;;:::i;8918:48::-;8914:246;;;8986:37;9001:6;;9008:1;9001:9;;;;;;;:::i;:::-;;;;;;;;;;12084:14;;;;:10;:14;;;;;;:26;;;;9012:10;12084:26;;;18050:24:2;18044:4;18037:38;18125:21;;;18117:30;;18109:39;18175:20;;18266:3;18262:16;;;18251:28;;;18242:38;;;18230:51;;;18208:74;;;-1:-1:-1;8147:119:2;8986:37:11;9055:4;9041:8;9050:1;9041:11;;;;;;;;:::i;:::-;:18;;;:11;;;;;;;;;;;:18;9109;;;;;8914:246;9201:3;;8864:365;;;;9304:16;9324:1;9304:21;9300:74;;9348:15;;;;;;;;;;;;;;9300:74;9417:63;1242:13:8;9463:16:11;9417:18;:63::i;14248:440:8:-;14328:18;14090:16;;;14132:24;14126:4;14119:38;14218:4;14202:21;;14194:30;;14186:39;;14180:46;;14493:17;14478:32;;14474:88;;;14533:18;;;;;;;;;;;;;;14474:88;14613:19;;;14622:10;14613:19;14609:73;;14655:16;;;;;;;;;;;;;;10924:327:11;11008:4;11024:41;11059:5;11024:34;:41::i;:::-;11128:31;11153:5;11128:24;:31::i;:::-;11124:99;;;11175:12;11181:5;11175;:12::i;:::-;-1:-1:-1;11208:4:11;11201:11;;11124:99;-1:-1:-1;11239:5:11;10924:327;;;;:::o;12618:464:8:-;12911:29;;;12898:9;:43;;;;12959:16;12955:111;;12995:56;13027:10;13039:11;12995:31;:56::i;9932:455::-;9996:4;10063:15;10075:2;10063:11;:15::i;:::-;13924:14;14090:16;;;14132:24;14126:4;14119:38;14218:4;14202:21;;14194:30;;14186:39;;14180:46;10178:29;10174:119;;-1:-1:-1;10277:5:8;;9932:455;-1:-1:-1;9932:455:8:o;10174:119::-;10338:21;10344:10;10356:2;10338:5;:21::i;:::-;-1:-1:-1;10376:4:8;;9932:455;-1:-1:-1;9932:455:8:o;6766:532:10:-;7144:10;;;7185:30;7144:10;;;;;;;:21;;7185:30;;;;;;;;;;;;;6851:7;;7225:40;1057:11:8;7157:8:10;7225:18;:40::i;2079:144:9:-;2129:13;2180:35;:2;2212:1;2180:22;:35::i;:::-;2161:55;;;;;;;;:::i;3719:157::-;3795:13;3846:3;3858:5;3827:42;;;;;;;;;:::i;:::-;;;;;;;;;;;;;3820:49;;3719:157;;;;:::o;2291:162::-;2345:13;2421:24;2427:8;2432:2;2427:4;:8::i;2421:24::-;2377:69;;;;;;;;:::i;2921:500::-;2973:13;2998:19;3020:26;;;;;;;;;;;;;;;;;;3036:9;3042:2;3036:5;:9::i;:::-;3020:6;:26::i;:::-;2998:48;;3060:15;3072:2;3060:11;:15::i;:::-;3056:359;;;3091:27;3121:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:6;:26::i;:::-;3236:49;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3256:14:9;;;:10;:14;;;;;;;;3091:56;;-1:-1:-1;3204:5:9;;3091:56;;3236:49;;3256:28;;:14;;:26;:28::i;3236:49::-;3168:136;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;3161:143;;;;2921:500;;;:::o;3056:359::-;3361:5;3373:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:6;:25::i;:::-;3342:62;;;;;;;;;:::i;:::-;;;;;;;;;;;;;3335:69;;;2921:500;;;:::o;3942:154::-;4021:13;4072:3;4083:5;4053:36;;;;;;;;;:::i;722:2559:3:-;835:20;961:4;955:11;983:10;980:2285;;;1183:1;1179;1167:10;1163:18;1159:26;1156:1;1152:34;1294:4;1288:11;1278:21;;1666:34;1660:4;1653:48;1793:6;1782:8;1775:16;1771:29;1735:34;1731:70;1725:4;1718:84;1908:4;1900:6;1896:17;1950:13;1945:3;1941:23;2040:623;2092:1;2086:4;2082:12;2074:20;;2154:4;2148:11;2294:4;2286:5;2282:2;2278:14;2274:25;2268:32;2265:1;2257:44;2359:4;2351:5;2347:2;2343:14;2339:25;2333:32;2330:1;2322:44;2423:4;2415:5;2412:1;2408:13;2404:24;2398:31;2395:1;2387:43;2479:4;2472:5;2468:16;2462:23;2459:1;2451:35;;2525:4;2519:11;2514:3;2507:24;2569:1;2564:3;2560:11;2553:18;;2630:3;2625;2622:12;2040:623;2612:33;2702:4;2693:14;2687:4;2680:28;2971:16;2847:1;2831:18;;2828:1;2824:26;2958:11;;;2951:37;;;;3136:1;3077:17;;3070:25;3066:33;;;3123:11;;;;3116:22;3208:21;;3193:37;;980:2285;;722:2559;;;;;:::o;2187:478:5:-;2434:1;2431;2428;2425;2417:6;2413:2;2406:5;2401:35;2391:258;;2542:10;2536:4;2529:24;2630:4;2624;2617:18;5429:1991:4;5536:17;5997:4;5993:9;5986:4;5977:6;5974:1;5970:14;5966:25;5962:41;5955:4;5949:11;5945:59;5938:66;;6075:4;6070:3;6066:14;6060:4;6053:28;6156:1;6151:3;6144:14;6243:3;6330:34;6324:4;6317:48;6413:6;6405;6401:19;6396:3;6392:29;6447:1;6443:6;6482:5;6668:288;6788:2;6778:13;;6772:20;6705:11;;;;6768:1;6759:11;;6751:42;6847:2;6840:4;6837:1;6833:12;6829:21;6823:28;6818:3;6810:42;6881:1;6877:12;6906:36;;;6668:288;6906:36;6973:4;6970:223;;;7086:10;7080:4;7073:24;7174:4;7168;7161:18;6970:223;-1:-1:-1;;;7268:13:4;;;7355:14;;;;7382:22;;;7355:14;5429:1991;-1:-1:-1;;5429:1991:4:o;2532:305:9:-;2581:13;2759:35;:2;2791:1;2759:22;:35::i;:::-;2613:217;;;;;;;;:::i;3490:183::-;3569:13;3634:3;3654:5;3601:65;;;;;;;;;:::i;11189:436:4:-;11248:17;11283:26;11303:5;11283:19;:26::i;:::-;11406:10;;11468:6;11456:19;;11418:1;11402:18;11521:11;;;;11566:22;;;11521:11;11189:436;-1:-1:-1;;11189:436:4:o;11762:1294::-;11829:17;11937:4;11931:11;11924:18;;12264:4;12259:3;12255:14;12249:4;12242:28;12355:34;12349:4;12342:48;12420:1;12415:3;12411:11;12404:18;;12447:2;12442:3;12435:15;12482:4;12477:3;12473:14;12519:1;12514:2;12511:1;12507:10;12500:21;12552:5;12548:2;12544:14;12535:23;;12755:1;12740:300;12805:1;12802;12798:9;12795:1;12791:17;12845:5;12842:1;12837:14;12903:2;12897:4;12893:13;12887:20;12883:1;12880;12876:9;12868:40;12949:4;12946:1;12942:12;12936:19;12933:1;12925:31;-1:-1:-1;;12985:1:4;12978:9;;;13007;;12740:300;13004:22;12744:14;;11762:1294;;;:::o;14:332:16:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;543:180;602:6;655:2;643:9;634:7;630:23;626:32;623:52;;;671:1;668;661:12;623:52;-1:-1:-1;694:23:16;;543:180;-1:-1:-1;543:180:16:o;728:367::-;791:8;801:6;855:3;848:4;840:6;836:17;832:27;822:55;;873:1;870;863:12;822:55;-1:-1:-1;896:20:16;;939:18;928:30;;925:50;;;971:1;968;961:12;925:50;1008:4;1000:6;996:17;984:29;;1068:3;1061:4;1051:6;1048:1;1044:14;1036:6;1032:27;1028:38;1025:47;1022:67;;;1085:1;1082;1075:12;1022:67;728:367;;;;;:::o;1100:841::-;1231:6;1239;1247;1255;1263;1316:2;1304:9;1295:7;1291:23;1287:32;1284:52;;;1332:1;1329;1322:12;1284:52;1372:9;1359:23;1401:18;1442:2;1434:6;1431:14;1428:34;;;1458:1;1455;1448:12;1428:34;1497:70;1559:7;1550:6;1539:9;1535:22;1497:70;:::i;:::-;1586:8;;-1:-1:-1;1471:96:16;-1:-1:-1;1674:2:16;1659:18;;1646:32;;-1:-1:-1;1690:16:16;;;1687:36;;;1719:1;1716;1709:12;1687:36;;1758:72;1822:7;1811:8;1800:9;1796:24;1758:72;:::i;:::-;1100:841;;;;-1:-1:-1;1849:8:16;1931:2;1916:18;1903:32;;1100:841;-1:-1:-1;;;;1100:841:16:o;1946:642::-;2111:2;2163:21;;;2233:13;;2136:18;;;2255:22;;;2082:4;;2111:2;2334:15;;;;2308:2;2293:18;;;2082:4;2377:185;2391:6;2388:1;2385:13;2377:185;;;2466:13;;2459:21;2452:29;2440:42;;2537:15;;;;2502:12;;;;2413:1;2406:9;2377:185;;;-1:-1:-1;2579:3:16;;1946:642;-1:-1:-1;;;;;;1946:642:16:o;2593:250::-;2678:1;2688:113;2702:6;2699:1;2696:13;2688:113;;;2778:11;;;2772:18;2759:11;;;2752:39;2724:2;2717:10;2688:113;;;-1:-1:-1;;2835:1:16;2817:16;;2810:27;2593:250::o;2848:455::-;2997:2;2986:9;2979:21;2960:4;3029:6;3023:13;3072:6;3067:2;3056:9;3052:18;3045:34;3088:79;3160:6;3155:2;3144:9;3140:18;3135:2;3127:6;3123:15;3088:79;:::i;:::-;3219:2;3207:15;3224:66;3203:88;3188:104;;;;3294:2;3184:113;;2848:455;-1:-1:-1;;2848:455:16:o;3539:196::-;3607:20;;3667:42;3656:54;;3646:65;;3636:93;;3725:1;3722;3715:12;3740:254;3808:6;3816;3869:2;3857:9;3848:7;3844:23;3840:32;3837:52;;;3885:1;3882;3875:12;3837:52;3908:29;3927:9;3908:29;:::i;:::-;3898:39;3984:2;3969:18;;;;3956:32;;-1:-1:-1;;;3740:254:16:o;4181:160::-;4246:20;;4302:13;;4295:21;4285:32;;4275:60;;4331:1;4328;4321:12;4346:505;4438:6;4446;4454;4507:2;4495:9;4486:7;4482:23;4478:32;4475:52;;;4523:1;4520;4513:12;4475:52;4563:9;4550:23;4596:18;4588:6;4585:30;4582:50;;;4628:1;4625;4618:12;4582:50;4667:70;4729:7;4720:6;4709:9;4705:22;4667:70;:::i;:::-;4756:8;;-1:-1:-1;4641:96:16;-1:-1:-1;4810:35:16;;-1:-1:-1;4841:2:16;4826:18;;4810:35;:::i;:::-;4800:45;;4346:505;;;;;:::o;4856:328::-;4933:6;4941;4949;5002:2;4990:9;4981:7;4977:23;4973:32;4970:52;;;5018:1;5015;5008:12;4970:52;5041:29;5060:9;5041:29;:::i;:::-;5031:39;;5089:38;5123:2;5112:9;5108:18;5089:38;:::i;:::-;5079:48;;5174:2;5163:9;5159:18;5146:32;5136:42;;4856:328;;;;;:::o;5189:322::-;5266:6;5274;5282;5335:2;5323:9;5314:7;5310:23;5306:32;5303:52;;;5351:1;5348;5341:12;5303:52;5374:29;5393:9;5374:29;:::i;:::-;5364:39;5450:2;5435:18;;5422:32;;-1:-1:-1;5501:2:16;5486:18;;;5473:32;;5189:322;-1:-1:-1;;;5189:322:16:o;5698:632::-;5869:2;5921:21;;;5991:13;;5894:18;;;6013:22;;;5840:4;;5869:2;6092:15;;;;6066:2;6051:18;;;5840:4;6135:169;6149:6;6146:1;6143:13;6135:169;;;6210:13;;6198:26;;6279:15;;;;6244:12;;;;6171:1;6164:9;6135:169;;6335:505;6430:6;6438;6446;6499:2;6487:9;6478:7;6474:23;6470:32;6467:52;;;6515:1;6512;6505:12;6467:52;6555:9;6542:23;6588:18;6580:6;6577:30;6574:50;;;6620:1;6617;6610:12;6574:50;6659:70;6721:7;6712:6;6701:9;6697:22;6659:70;:::i;:::-;6748:8;;6633:96;;-1:-1:-1;6830:2:16;6815:18;;;;6802:32;;6335:505;-1:-1:-1;;;;6335:505:16:o;6845:186::-;6904:6;6957:2;6945:9;6936:7;6932:23;6928:32;6925:52;;;6973:1;6970;6963:12;6925:52;6996:29;7015:9;6996:29;:::i;7619:248::-;7684:6;7692;7745:2;7733:9;7724:7;7720:23;7716:32;7713:52;;;7761:1;7758;7751:12;7713:52;7797:9;7784:23;7774:33;;7826:35;7857:2;7846:9;7842:18;7826:35;:::i;:::-;7816:45;;7619:248;;;;;:::o;7872:254::-;7937:6;7945;7998:2;7986:9;7977:7;7973:23;7969:32;7966:52;;;8014:1;8011;8004:12;7966:52;8037:29;8056:9;8037:29;:::i;:::-;8027:39;;8085:35;8116:2;8105:9;8101:18;8085:35;:::i;8131:437::-;8217:6;8225;8278:2;8266:9;8257:7;8253:23;8249:32;8246:52;;;8294:1;8291;8284:12;8246:52;8334:9;8321:23;8367:18;8359:6;8356:30;8353:50;;;8399:1;8396;8389:12;8353:50;8438:70;8500:7;8491:6;8480:9;8476:22;8438:70;:::i;:::-;8527:8;;8412:96;;-1:-1:-1;8131:437:16;-1:-1:-1;;;;8131:437:16:o;8573:579::-;8677:6;8685;8693;8701;8754:2;8742:9;8733:7;8729:23;8725:32;8722:52;;;8770:1;8767;8760:12;8722:52;8793:29;8812:9;8793:29;:::i;:::-;8783:39;;8873:2;8862:9;8858:18;8845:32;8900:18;8892:6;8889:30;8886:50;;;8932:1;8929;8922:12;8886:50;8971:70;9033:7;9024:6;9013:9;9009:22;8971:70;:::i;:::-;8573:579;;9060:8;;-1:-1:-1;8945:96:16;;9142:2;9127:18;9114:32;;8573:579;-1:-1:-1;;;;8573:579:16:o;9157:248::-;9225:6;9233;9286:2;9274:9;9265:7;9261:23;9257:32;9254:52;;;9302:1;9299;9292:12;9254:52;-1:-1:-1;;9325:23:16;;;9395:2;9380:18;;;9367:32;;-1:-1:-1;9157:248:16:o;9410:808::-;9507:6;9515;9523;9531;9539;9592:3;9580:9;9571:7;9567:23;9563:33;9560:53;;;9609:1;9606;9599:12;9560:53;9632:29;9651:9;9632:29;:::i;:::-;9622:39;;9680:38;9714:2;9703:9;9699:18;9680:38;:::i;:::-;9670:48;;9765:2;9754:9;9750:18;9737:32;9727:42;;9820:2;9809:9;9805:18;9792:32;9843:18;9884:2;9876:6;9873:14;9870:34;;;9900:1;9897;9890:12;9870:34;9938:6;9927:9;9923:22;9913:32;;9983:7;9976:4;9972:2;9968:13;9964:27;9954:55;;10005:1;10002;9995:12;9954:55;10045:2;10032:16;10071:2;10063:6;10060:14;10057:34;;;10087:1;10084;10077:12;10057:34;10132:7;10127:2;10118:6;10114:2;10110:15;10106:24;10103:37;10100:57;;;10153:1;10150;10143:12;10100:57;9410:808;;;;-1:-1:-1;9410:808:16;;-1:-1:-1;10184:2:16;10176:11;;10206:6;9410:808;-1:-1:-1;;;9410:808:16:o;10223:316::-;10300:6;10308;10316;10369:2;10357:9;10348:7;10344:23;10340:32;10337:52;;;10385:1;10382;10375:12;10337:52;-1:-1:-1;;10408:23:16;;;10478:2;10463:18;;10450:32;;-1:-1:-1;10529:2:16;10514:18;;;10501:32;;10223:316;-1:-1:-1;10223:316:16:o;10749:260::-;10817:6;10825;10878:2;10866:9;10857:7;10853:23;10849:32;10846:52;;;10894:1;10891;10884:12;10846:52;10917:29;10936:9;10917:29;:::i;:::-;10907:39;;10965:38;10999:2;10988:9;10984:18;10965:38;:::i;11199:354::-;11268:34;11335:10;;;11323;;;11319:27;;11358:12;;;11355:192;;;11403:77;11400:1;11393:88;11504:4;11501:1;11494:15;11532:4;11529:1;11522:15;11355:192;;11199:354;;;;:::o;11558:184::-;11610:77;11607:1;11600:88;11707:4;11704:1;11697:15;11731:4;11728:1;11721:15;12845:184;12897:77;12894:1;12887:88;12994:4;12991:1;12984:15;13018:4;13015:1;13008:15;13034:451;13286:31;13281:3;13274:44;13256:3;13347:6;13341:13;13363:75;13431:6;13426:2;13421:3;13417:12;13410:4;13402:6;13398:17;13363:75;:::i;:::-;13458:16;;;;13476:2;13454:25;;13034:451;-1:-1:-1;;13034:451:16:o;13563:1911::-;14456:3;14451;14444:16;14426:3;14489:6;14483:13;14505:74;14572:6;14568:1;14563:3;14559:11;14552:4;14544:6;14540:17;14505:74;:::i;:::-;14607:6;14602:3;14598:16;14588:26;;14633:3;14664:2;14660:1;14656:2;14652:10;14645:22;14698:6;14692:13;14714:75;14780:8;14776:1;14772:2;14768:10;14761:4;14753:6;14749:17;14714:75;:::i;:::-;14849:1;14808:17;;14841:10;;;14834:22;;;14881:13;;14903:75;14881:13;14965:1;14957:10;;14950:4;14938:17;;14903:75;:::i;:::-;15038:1;14997:17;;15030:10;;;15023:22;;;15070:13;;15092:75;15070:13;15154:1;15146:10;;15139:4;15127:17;;15092:75;:::i;:::-;15227:1;15186:17;;15219:10;;;15212:22;15259:13;;15281:75;15259:13;15343:1;15335:10;;15328:4;15316:17;;15281:75;:::i;:::-;15375:17;15401:41;15439:1;15431:10;;13552:3;13540:16;;13490:68;15401:41;15466:1;15458:10;;13563:1911;-1:-1:-1;;;;;;;13563:1911:16:o;15479:420::-;15730:3;15725;15718:16;15700:3;15763:6;15757:13;15779:74;15846:6;15842:1;15837:3;15833:11;15826:4;15818:6;15814:17;15779:74;:::i;:::-;15873:16;;;;15891:1;15869:24;;15479:420;-1:-1:-1;;15479:420:16:o;15904:1037::-;16353:3;16381:66;16468:2;16463:3;16456:15;16500:6;16494:13;16516:74;16583:6;16579:1;16574:3;16570:11;16563:4;16555:6;16551:17;16516:74;:::i;:::-;16653:66;16649:1;16609:16;;;16641:10;;;16634:86;16745:13;;16767:75;16745:13;16829:1;16821:10;;16814:4;16802:17;;16767:75;:::i;:::-;16861:17;16902:1;16894:10;;16887:22;;;;16933:1;16925:10;;;-1:-1:-1;;;;15904:1037:16:o;16946:448::-;17198:28;17193:3;17186:41;17168:3;17256:6;17250:13;17272:75;17340:6;17335:2;17330:3;17326:12;17319:4;17311:6;17307:17;17272:75;:::i;:::-;17367:16;;;;17385:2;17363:25;;16946:448;-1:-1:-1;;16946:448:16:o;17399:1239::-;18016:3;18011;18004:16;17986:3;18049:6;18043:13;18065:74;18132:6;18128:1;18123:3;18119:11;18112:4;18104:6;18100:17;18065:74;:::i;:::-;18167:6;18162:3;18158:16;18148:26;;18193:3;18224:2;18220:1;18216:2;18212:10;18205:22;18258:6;18252:13;18274:75;18340:8;18336:1;18332:2;18328:10;18321:4;18313:6;18309:17;18274:75;:::i;:::-;18409:1;18368:17;;18401:10;;;18394:22;18441:13;;18463:75;18441:13;18525:1;18517:10;;18510:4;18498:17;;18463:75;:::i;:::-;18602:3;18598:1;18557:17;;;;18590:10;;;18583:23;18630:1;18622:10;;17399:1239;-1:-1:-1;;;;;17399:1239:16:o;18643:891::-;19122:3;19117;19110:16;19092:3;19155:6;19149:13;19171:74;19238:6;19234:1;19229:3;19225:11;19218:4;19210:6;19206:17;19171:74;:::i;:::-;19308:3;19304:1;19264:16;;;19296:10;;;19289:23;19337:13;;19359:75;19337:13;19421:1;19413:10;;19406:4;19394:17;;19359:75;:::i;:::-;19498:3;19494:1;19453:17;;;;19486:10;;;19479:23;19526:1;19518:10;;18643:891;-1:-1:-1;;;;18643:891:16:o;19539:874::-;19928:66;19923:3;19916:79;19898:3;20024:6;20018:13;20040:74;20107:6;20103:1;20098:3;20094:11;20087:4;20079:6;20075:17;20040:74;:::i;:::-;20177:66;20173:1;20133:16;;;20165:10;;;20158:86;20269:13;;20291:75;20269:13;20353:1;20345:10;;20338:4;20326:17;;20291:75;:::i;:::-;20386:17;20405:1;20382:25;;19539:874;-1:-1:-1;;;;19539:874:16:o;20418:996::-;20771:66;20766:3;20759:79;20868:66;20863:2;20858:3;20854:12;20847:88;20965:66;20960:2;20955:3;20951:12;20944:88;21062:66;21057:2;21052:3;21048:12;21041:88;20741:3;21158:6;21152:13;21174:74;21241:6;21235:3;21230;21226:13;21221:2;21213:6;21209:15;21174:74;:::i;:::-;21313:66;21307:3;21267:16;;;;21299:12;;;21292:88;-1:-1:-1;21404:3:16;21396:12;;20418:996;-1:-1:-1;20418:996:16:o;21419:1087::-;21900:66;21895:3;21888:79;21870:3;21996:6;21990:13;22012:75;22080:6;22075:2;22070:3;22066:12;22059:4;22051:6;22047:17;22012:75;:::i;:::-;22151:66;22146:2;22106:16;;;22138:11;;;22131:87;22243:13;;22265:76;22243:13;22327:2;22319:11;;22312:4;22300:17;;22265:76;:::i;:::-;22406:66;22401:2;22360:17;;;;22393:11;;;22386:87;22497:2;22489:11;;21419:1087;-1:-1:-1;;;;21419:1087:16:o

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

Open Edition minting until 29 June, 2023; 16,777,216 theoretical max supply. XXYYZZ is a fun onchain experiment in the NFT space exploring the realm of onchain identity, scarcity, composability, and finality. We aren't the first to create color NFTs and we certainly won't be t...

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.