ETH Price: $2,449.26 (+1.49%)
 

Overview

Max Total Supply

106 Ͼ721

Holders

23

Total Transfers

-

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

CryptoPunks were created before the ERC-721 standard for non fungible tokens existed. For this reason CryptoPunks are only tradable on the CryptoPunks App. Yuga Labs created a wrapper for CryptoPunk holders to wrap their Punks into ERC-721 tokens. Wrapping a CryptoPunk converts it to an ERC-721 enabling you to interact with other marketplaces and defi applications. For more information go to https://721.cryptopunks.app/

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
CryptoPunks721

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, MIT license
File 1 of 13 : CryptoPunks721.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import {IStashFactory} from "../interfaces/IStashFactory.sol";
import {ICryptoPunks} from "../interfaces/ICryptoPunks.sol";
import {IStash} from "../interfaces/IStash.sol";
import {ILegacyWrappedPunks} from "../interfaces/ILegacyWrappedPunks.sol";
import {CryptoPunks721Metadata} from "./CryptoPunks721Metadata.sol";
import {Base64} from "solady/utils/Base64.sol";
import {ERC721} from "solady/tokens/ERC721.sol";

/**
 * @title CryptoPunks721
 * @notice A modern wrapper to enable ERC721 functionality for CryptoPunks.
 */
contract CryptoPunks721 is ERC721, CryptoPunks721Metadata {
    error NotPunkOwner();
    error PunkIsOwned();

    IStashFactory private immutable _stashFactory;
    ICryptoPunks internal immutable _cryptoPunks;
    ILegacyWrappedPunks internal immutable _legacyWrapper;

    constructor(address stashFactory, address cryptoPunks, address legacyWrapper, address _punksMetadata)
        CryptoPunks721Metadata(_punksMetadata)
    {
        _stashFactory = IStashFactory(stashFactory);
        _cryptoPunks = ICryptoPunks(cryptoPunks);
        _legacyWrapper = ILegacyWrappedPunks(legacyWrapper);
    }

    function name() public pure override returns (string memory) {
        return "CryptoPunks 721";
    }

    function symbol() public pure override returns (string memory) {
        return unicode"Ͼ721";
    }

    function licensingTerms() public pure returns (string memory) {
        return "https://licenseterms.cryptopunks.app/";
    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        // allow retrieving metadata for all valid wrapped punks, even if not (currently) wrapped.
        if (tokenId >= 10000) {
            revert TokenDoesNotExist();
        }
        return string.concat("data:application/json;base64,", Base64.encode(bytes(stringURI(tokenId))));
    }

    /**
     * @notice Wrap a CryptoPunk. Requires that the user has transferred their punk to their Stash.
     * @dev If the user does not have a Stash, one will be deployed for them.
     * @param punkIndex The index of the punk to wrap.
     */
    function wrapPunk(uint256 punkIndex) external {
        address stash = _stashFactory.stashAddressFor(msg.sender);

        uint256 size;
        assembly {
            size := extcodesize(stash)
        }

        if (size == 0) {
            _stashFactory.deployStash(msg.sender);
        }

        IStash(stash).wrapPunk(punkIndex);
        _mint(msg.sender, punkIndex);
    }

    /**
     * @notice Wrap multiple CryptoPunks. Requires that the user has transferred their punks to their Stash.
     * @dev If the user does not have a Stash, one will be deployed for them.
     * @param punkIndexes An array of indexes of punks to wrap.
     */
    function wrapPunkBatch(uint256[] calldata punkIndexes) external {
        address stash = _stashFactory.stashAddressFor(msg.sender);

        uint256 size;
        assembly {
            size := extcodesize(stash)
        }

        if (size == 0) {
            _stashFactory.deployStash(msg.sender);
        }

        for (uint256 i = 0; i < punkIndexes.length; ++i) {
            uint256 punkIndex = punkIndexes[i];

            IStash(stash).wrapPunk(punkIndex);
            _mint(msg.sender, punkIndex);
        }
    }

    /**
     * @notice Unwrap a CryptoPunk. Requires that the caller owns or is approved to transfer the wrapped CryptoPunk.
     * @param punkIndex The index of the punk to unwrap
     */
    function unwrapPunk(uint256 punkIndex) external {
        _burn(msg.sender, punkIndex);
        _cryptoPunks.transferPunk(msg.sender, punkIndex);
    }

    /**
     * @notice Unwrap multiple CryptoPunks. Requires that the caller owns or is approved to transfer the wrapped CryptoPunks.
     * @param punkIndexes An array of indexes of punks to unwrap
     */
    function unwrapPunkBatch(uint256[] calldata punkIndexes) external {
        for (uint256 i = 0; i < punkIndexes.length; i++) {
            uint256 punkIndex = punkIndexes[i];

            _burn(msg.sender, punkIndex);
            _cryptoPunks.transferPunk(msg.sender, punkIndex);
        }
    }

    /**
     * @notice Bulk migration tool to move legacy wrapped punks into the new wrapper.
     * @param punkIndexes The indexes of the punks to migrate. Must be owned by the caller.
     */
    function migrateLegacyWrappedPunks(uint256[] calldata punkIndexes) external {
        for (uint256 i = 0; i < punkIndexes.length; ++i) {
            uint256 punkIndex = punkIndexes[i];
            _legacyWrapper.transferFrom(msg.sender, address(this), punkIndex);
            _legacyWrapper.burn(punkIndex);
            _mint(msg.sender, punkIndex);
        }
    }

    /**
     * @dev Used for rescuing punks stuck in the contract, which would otherwise be trapped.
     * Punks that are properly wrapped can NOT be "rescued". This is open to the public so that
     * CryptoPunks Wrapped can remain open and ownerless. The alternatives are to either assign
     * an owner to the contract to manage withdrawing mistakenly deposited CryptoPunks, or to
     * allow the CryptoPunks to be trapped forever. Both of these alternatives were deemed
     * less desirable.
     */
    function rescuePunk(uint256 punkIndex) external {
        if (_exists(punkIndex)) revert PunkIsOwned();
        _cryptoPunks.transferPunk(msg.sender, punkIndex);
    }

    /**
     * @notice Returns the address of the Stash for a given user.
     * @param user The user to get the Stash for.
     */
    function punkProxyForUser(address user) external view returns (address) {
        return _stashFactory.stashAddressFor(user);
    }

    /**
     * @notice Adapted from https://github.com/chiru-labs/ERC721A/blob/main/contracts/extensions/ERC721AQueryable.sol
     * @dev Returns an array of token IDs owned by `owner`.
     *
     * This function scans the ownership mapping and is O(`totalSupply`) in complexity.
     * It is meant to be called off-chain.
     */
    function tokensOfOwner(address owner) external view returns (uint256[] memory) {
        unchecked {
            uint256 tokenIdsIdx;
            uint256 tokenIdsLength = balanceOf(owner);
            uint256[] memory tokenIds = new uint256[](tokenIdsLength);

            for (uint256 i = 0; tokenIdsIdx != tokenIdsLength; ++i) {
                address tokenOwner = _ownerOf(i);
                if (tokenOwner == owner) {
                    tokenIds[tokenIdsIdx++] = i;
                }
            }
            return tokenIds;
        }
    }

    /**
     * @notice Returns the total number of CryptoPunks that have been wrapped.
     * @dev This total can be off if punks have been mistakenly deposited to the wrapper contract.
     * However, any mistakenly deposited punks are free to be withdrawn by anybody and thus should
     * theoretically not last in the contract for more than a block.
     */
    function totalSupply() external view returns (uint256) {
        return _cryptoPunks.balanceOf(address(this)); 
    }
}

File 2 of 13 : IStashFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

interface IStashFactory {
    function isStash(address stash) external view returns (bool);
    function deployStash(address owner) external returns (address);
    function isAuction(address auction) external view returns (bool);
    function stashAddressFor(address owner) external view returns (address);
}

File 3 of 13 : ICryptoPunks.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

interface ICryptoPunks {
    function punksOfferedForSale(uint256)
        external
        view
        returns (bool isForSale, uint256 punkIndex, address seller, uint256 minValue, address onlySellTo);
    function buyPunk(uint256) external payable;
    function transferPunk(address, uint256) external;
    function balanceOf(address) external view returns (uint256);
    function punkIndexToAddress(uint256) external view returns (address);
    function pendingWithdrawals(address) external view returns (uint256);
    function offerPunkForSaleToAddress(uint256, uint256, address) external;
    function getPunk(uint256 punkId) external;
}

File 4 of 13 : IStash.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {OrderType} from "../helpers/Enum.sol";
import {Order} from "../helpers/Struct.sol";

interface IStash {
    function placeOrder(uint80 pricePerUnit, uint16 numberOfUnits) external payable;
    function processOrder(uint80 pricePerUnit, uint16 numberOfUnits) external;
    function availableLiquidity(address tokenAddress) external view returns (uint256);
    function wrapPunk(uint256 punkIndex) external;
    function getOrder(address paymentToken) external view returns (Order memory);
    function withdraw(address tokenAddress, uint256 amount) external;
    function owner() external view returns (address);
    function version() external view returns (uint256);
}

File 5 of 13 : ILegacyWrappedPunks.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

interface ILegacyWrappedPunks {
    function transferFrom(address from, address to, uint256 tokenId) external;
    function proxyInfo(address) external view returns (address);
    function registerProxy() external;
    function burn(uint256 punkId) external;
    function mint(uint256 punkId) external;
    function approve(address to, uint256 punkId) external;
    function ownerOf(uint256 punkId) external view returns (address);
}

File 6 of 13 : CryptoPunks721Metadata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {ICryptoPunksData} from "../interfaces/ICryptoPunksData.sol";
import {json} from "sol-json/json.sol";
import {Base64} from "solady/utils/Base64.sol";
import {LibString} from "solady/utils/LibString.sol";

/**
 * @title  CryptoPunksWrappedMetadata
 * @author Modified from James Wenzel (emo.eth) (https://github.com/emo-eth/wrapped-punks/blob/main/src/PunksWrapperMetadata.sol)
 * @notice Abstract contract to fetch and format metadata for wrapped Punks.
 */
abstract contract CryptoPunks721Metadata {
    ICryptoPunksData public immutable PUNKS_DATA;

    constructor(address _punksData) {
        PUNKS_DATA = ICryptoPunksData(_punksData);
    }

    string private constant _BACKGROUND_FILL = '<rect width="100%" height="100%" fill="#66A670"/>';

    /**
     * @dev Returns the string URI for a given token ID.
     * @param tokenId The index of the punk to get the URI for
     */
    function stringURI(uint256 tokenId) internal view returns (string memory) {
        uint16 punkIndex = uint16(tokenId);
        string memory imageData = PUNKS_DATA.punkImageSvg(punkIndex);
        imageData = LibString.slice(imageData, 24);

        imageData = LibString.concat(
            LibString.slice(imageData, 0, 74), LibString.concat(_BACKGROUND_FILL, LibString.slice(imageData, 74))
        );

        string memory attributes = PUNKS_DATA.punkAttributes(punkIndex);

        attributes = parseAttributesArray(attributes);
        return json.object(
            string.concat(
                json.property("image", string.concat("data:image/svg+xml;base64,", Base64.encode(bytes(imageData)))),
                ",",
                json.rawProperty("attributes", attributes)
            )
        );
    }

    /**
     * @dev Parse a comma-separated list of attributes into a JSON array of attributes. Also calculates and appends an
     *      "Attribute Count" attribute.
     * @param attributes The attributes string to parse
     */
    function parseAttributesArray(string memory attributes) internal pure returns (string memory parsed) {
        string[] memory individualTraits = LibString.split(attributes, string(", "));
        bytes1 firstChar = bytes(individualTraits[0])[0];
        // only humans have skin tones, and their "type" always starts with M or F
        bool isHuman = firstChar == "M" || firstChar == "F";
        string[] memory attributesArray;
        // placeholder if human
        string[] memory typeAndSkinToneIfHuman;
        if (isHuman) {
            // include an extra attribute for "Attribute Count" and an extra for "Skin Tone"
            attributesArray = new string[](individualTraits.length + 2);
            typeAndSkinToneIfHuman = LibString.split(individualTraits[0], " ");
            attributesArray[0] = createAttribute("Type", typeAndSkinToneIfHuman[0]);
        } else {
            attributesArray = new string[](individualTraits.length + 1);
            attributesArray[0] = createAttribute("Type", individualTraits[0]);
        }
        // "type" is not traditionally counted in the attribute count, nor is skin tone
        uint256 count = individualTraits.length - 1;

        // cryptopunks website refers to remaining attributes just as "Attributes" (versus OpenSea's "Accessories")
        string memory trait = "Attribute";
        // start at 1 to skip "Type"; iterate over remaining attributes, if any
        for (uint256 i = 1; i < individualTraits.length; i++) {
            attributesArray[i] = createAttribute(trait, individualTraits[i]);
        }

        // add "Attribute Count" meta-attribute
        attributesArray[individualTraits.length] = createAttribute("Attribute Count", LibString.toString(count));

        if (isHuman) {
            // add "Skin Tone" meta-attribute
            attributesArray[individualTraits.length + 1] = createAttribute("Skin Tone", typeAndSkinToneIfHuman[1]);
        }

        // concat all attributes into a single JSON array
        return json.arrayOf(attributesArray);
    }

    /**
     * @dev Create a single attribute JSON object.
     */
    function createAttribute(string memory trait, string memory value) internal pure returns (string memory) {
        return json.object(string.concat(json.property("trait_type", trait), ",", json.property("value", value)));
    }
}

File 7 of 13 : 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 0x0670 will turn "-_" into "+/".
                mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
                mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670)))

                // 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 8 of 13 : 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)
///
/// @dev 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.
/// - For performance, methods are made payable where permitted by the ERC721 standard.
/// - The `safeTransfer` functions use the identity precompile (0x4)
///   to copy memory internally.
///
/// If you are overriding:
/// - NEVER violate the ERC721 invariant:
///   the balance of an owner MUST always be equal to their number of ownership slots.
///   The transfer functions do not have an underflow guard for user token balances.
/// - Make sure all variables written to storage are properly cleaned
//    (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood).
/// - Check that the overridden function is actually used in the function you want to
///   change the behavior of. Much of the code has been manually inlined for performance.
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..255] `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..255] `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 manage 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(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 an {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 an {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)
            // forgefmt: disable-next-item
            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(codesize(), 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 := iszero(iszero(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             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance, no events are emitted for the hitchhiking setters.
    // Please emit your own events if required.

    /// @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(codesize(), 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(codesize(), 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 manage 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 manage the token.
                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(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id)
        }
    }

    /// @dev Approve or remove the `operator` as an operator for `by`,
    /// without authorization checks.
    ///
    /// Emits an {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(codesize(), 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(m, 0x00, returndatasize())
                    revert(m, returndatasize())
                }
            }
            // Load the returndata and compare it.
            if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
                mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

File 9 of 13 : Enum.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

enum OrderType
{
    // 0: Can replace previous bid. Alters bid price and adds `numberOfUnits`
    SUBSEQUENT_BIDS_OVERWRITE_PRICE_AND_ADD_UNITS,
    // 1: Can replace previous bid if new bid has higher `pricePerUnit`
    SUBSEQUENT_BIDS_REPLACE_EXISTING_PRICE_INCREASE_REQUIRED,
    // 2: Cannot replace previous bid under any circumstance
    UNREPLACEABLE
}

File 10 of 13 : Struct.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {OrderType} from "./Enum.sol";

struct Order {
    uint16 numberOfUnits;
    uint80 pricePerUnit;
    address auction;
}

struct PunkBid {
    Order order;
    uint256 accountNonce;
    uint256 bidNonce;
    uint256 expiration;
    bytes32 root;
}

File 11 of 13 : ICryptoPunksData.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

interface ICryptoPunksData {
    function addAsset(uint8 index, bytes memory encoding, string memory name) external;
    function addComposites(
        uint64 key1,
        uint32 value1,
        uint64 key2,
        uint32 value2,
        uint64 key3,
        uint32 value3,
        uint64 key4,
        uint32 value4
    ) external;
    function addPunks(uint8 index, bytes memory _punks) external;
    function punkAttributes(uint16 index) external view returns (string memory text);
    function punkImage(uint16 index) external view returns (bytes memory);
    function punkImageSvg(uint16 index) external view returns (string memory svg);
    function sealContract() external;
    function setPalette(bytes memory _palette) external;
}

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

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

library json {
    using LibString for string;

    /**
     * @notice enclose a string in {braces}
     *         Note: does not escape quotes in value
     * @param  value string to enclose in braces
     * @return string of {value}
     */
    function object(string memory value) internal pure returns (string memory) {
        return string.concat("{", value, "}");
    }

    /**
     * @notice enclose a string in [brackets]
     *         Note: does not escape quotes in value
     * @param value string to enclose in brackets
     * @return string of [value]
     */
    function array(string memory value) internal pure returns (string memory) {
        return string.concat("[", value, "]");
    }

    /**
     * @notice enclose name and value with quotes, and place a colon "between":"them".
     *         Note: escapes quotes in name and value
     * @param name name of property
     * @param value value of property
     * @return string of "name":"value"
     */
    function property(string memory name, string memory value) internal pure returns (string memory) {
        return string.concat('"', name.escapeJSON(), '":"', value.escapeJSON(), '"');
    }

    /**
     * @notice enclose name with quotes, but not rawValue, and place a colon "between":them
     *         Note: escapes quotes in name, but not value (which may itself be a JSON object, array, etc)
     * @param name name of property
     * @param rawValue raw value of property, which will not be enclosed in quotes
     * @return string of "name":value
     */
    function rawProperty(string memory name, string memory rawValue) internal pure returns (string memory) {
        return string.concat('"', name.escapeJSON(), '":', rawValue);
    }

    /**
     * @notice comma-join an array of properties and {"enclose":"them","in":"braces"}
     *         Note: does not escape quotes in properties, as it assumes they are already escaped
     * @param properties array of '"name":"value"' properties to join
     * @return string of {"name":"value","name":"value",...}
     */
    function objectOf(string[] memory properties) internal pure returns (string memory) {
        if (properties.length == 0) {
            return object("");
        }
        string memory result = properties[0];
        for (uint256 i = 1; i < properties.length; ++i) {
            result = string.concat(result, ",", properties[i]);
        }
        return object(result);
    }

    /**
     * @notice comma-join an array of values and enclose them [in,brackets]
     *         Note: does not escape quotes in values, as it assumes they are already escaped
     * @param values array of values to join
     * @return string of [value,value,...]
     */
    function arrayOf(string[] memory values) internal pure returns (string memory) {
        return array(_commaJoin(values));
    }

    /**
     * @notice comma-join two arrays of values and [enclose,them,in,brackets]
     *         Note: does not escape quotes in values, as it assumes they are already escaped
     * @param values1 first array of values to join
     * @param values2 second array of values to join
     * @return string of [values1_0,values1_1,values2_0,values2_1...]
     */
    function arrayOf(string[] memory values1, string[] memory values2) internal pure returns (string memory) {
        if (values1.length == 0) {
            return arrayOf(values2);
        } else if (values2.length == 0) {
            return arrayOf(values1);
        }
        return array(string.concat(_commaJoin(values1), ",", _commaJoin(values2)));
    }

    /**
     * @notice enclose a string in double "quotes", escaping any existing quotes
     * @param str string to enclose in quotes
     * @return string of "value"
     */
    function quote(string memory str) internal pure returns (string memory) {
        return string.concat('"', str.escapeJSON(), '"');
    }

    /**
     * @notice comma-join an array of strings
     * @param values array of strings to join
     * @return string of value,value,...
     */
    function _commaJoin(string[] memory values) internal pure returns (string memory) {
        return _join(values, ",");
    }

    /**
     * @notice join two strings with a comma
     * @param value1 first string
     * @param value2 second string
     * @return string of value1,value2
     */
    function _commaJoin(string memory value1, string memory value2) internal pure returns (string memory) {
        return string.concat(value1, ",", value2);
    }

    /**
     * @notice join an array of strings with a specified separator
     * @param values array of strings to join
     * @param separator separator to join with
     * @return string of value<separator>value<separator>...
     */
    function _join(string[] memory values, string memory separator) internal pure returns (string memory) {
        if (values.length == 0) {
            return "";
        }
        string memory result = values[0];
        for (uint256 i = 1; i < values.length; ++i) {
            result = string.concat(result, separator, values[i]);
        }
        return result;
    }
}

File 13 of 13 : 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();

    /// @dev The length of the string is more than 32 bytes.
    error TooBigForSmallString();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         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 {
                mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
                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 prefixed with "0x".
    /// The output excludes leading "0" from the `toHexString` output.
    /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
    function toMinimalHexString(uint256 value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero.
            str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.
            mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output excludes leading "0" from the `toHexStringNoPrefix` output.
    /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
    function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
            let strLength := mload(str) // Get the length.
            str := add(str, o) // Move the pointer, accounting for leading zero.
            mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
        }
    }

    /// @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 toHexStringChecksummed(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 true if `search` is found in `subject`, false otherwise.
    function contains(string memory subject, string memory search) internal pure returns (bool) {
        return indexOf(subject, search) != NOT_FOUND;
    }

    /// @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(aLength, 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, aLength)
            // 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 string from a small bytes32 string.
    /// `s` must be null-terminated, or behavior will be undefined.
    function fromSmallString(bytes32 s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let n := 0
            for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
            mstore(result, n)
            let o := add(result, 0x20)
            mstore(o, s)
            mstore(add(o, n), 0)
            mstore(0x40, add(result, 0x40))
        }
    }

    /// @dev Returns the small string, with all bytes after the first null byte zeroized.
    function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
            mstore(0x00, s)
            mstore(result, 0x00)
            result := mload(0x00)
        }
    }

    /// @dev Returns the string as a normalized null-terminated small string.
    function toSmallString(string memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(s)
            if iszero(lt(result, 33)) {
                mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
                revert(0x1c, 0x04)
            }
            result := shl(shl(3, sub(32, result)), mload(add(s, result)))
        }
    }

    /// @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 {
            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))
            for {} 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.
    /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
    function escapeJSON(string memory s, bool addDoubleQuotes)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let end := add(s, mload(s))
            result := add(mload(0x40), 0x20)
            if addDoubleQuotes {
                mstore8(result, 34)
                result := add(1, result)
            }
            // 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))
            for {} 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)
            }
            if addDoubleQuotes {
                mstore8(result, 34)
                result := add(1, result)
            }
            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) {
        result = escapeJSON(s, false);
    }

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

    /// @dev Returns whether `a` equals `b`. For small strings up to 32 bytes.
    /// `b` must be null-terminated and normalized, or behavior will be undefined.
    /// See: `normalizeSmallString`.
    function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            // These should be evaluated on compile time, as far as possible.
            let x := and(b, add(not(b), 1))
            let r := or(shl(8, iszero(b)), shl(7, iszero(iszero(shr(128, x)))))
            r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            result := gt(eq(mload(a), sub(32, shr(3, r))), shr(r, xor(b, mload(add(a, 0x20)))))
        }
    }

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

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "ERC721A/=lib/ERC721A/contracts/",
    "solady/=lib/solady/src/",
    "soladytest/=lib/solady/test/",
    "sol-json/=lib/sol-json/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "solmate/=lib/sol-json/lib/solady/lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"stashFactory","type":"address"},{"internalType":"address","name":"cryptoPunks","type":"address"},{"internalType":"address","name":"legacyWrapper","type":"address"},{"internalType":"address","name":"_punksMetadata","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"NotPunkOwner","type":"error"},{"inputs":[],"name":"PunkIsOwned","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"},{"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":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":"PUNKS_DATA","outputs":[{"internalType":"contract ICryptoPunksData","name":"","type":"address"}],"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":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"licensingTerms","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"punkIndexes","type":"uint256[]"}],"name":"migrateLegacyWrappedPunks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","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":"user","type":"address"}],"name":"punkProxyForUser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"punkIndex","type":"uint256"}],"name":"rescuePunk","outputs":[],"stateMutability":"nonpayable","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":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"punkIndex","type":"uint256"}],"name":"unwrapPunk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"punkIndexes","type":"uint256[]"}],"name":"unwrapPunkBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"punkIndex","type":"uint256"}],"name":"wrapPunk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"punkIndexes","type":"uint256[]"}],"name":"wrapPunkBatch","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101006040523480156200001257600080fd5b50604051620026dd380380620026dd833981016040819052620000359162000076565b6001600160a01b0390811660805292831660a05290821660c0521660e052620000d3565b80516001600160a01b03811681146200007157600080fd5b919050565b600080600080608085870312156200008d57600080fd5b620000988562000059565b9350620000a86020860162000059565b9250620000b86040860162000059565b9150620000c86060860162000059565b905092959194509250565b60805160a05160c05160e0516125916200014c60003960008181610cc60152610d360152600081816105c101528181610c100152610f600152600081816104e8015281816108b40152818161094901528181610a3c0152610ad10152600081816102ab015281816112c301526113ac01526125916000f3fe60806040526004361061014b5760003560e01c806390aaf2ff116100b6578063b88d4fde1161006f578063b88d4fde14610408578063c87b56dd1461041b578063cbc307021461043b578063df53b5c11461045b578063e4a5016d14610470578063e985e9c51461049057600080fd5b806390aaf2ff1461033a57806395d89b411461035a5780639e88cf42146103885780639f8f573f146103a8578063a14aad90146103c8578063a22cb465146103e857600080fd5b806323b872dd1161010857806323b872dd1461027357806342842e0e146102865780634ed9a045146102995780636352211e146102cd57806370a08231146102ed5780638462151c1461030d57600080fd5b806301ffc9a71461015057806306fdde03146101a257806307f2a9b1146101e3578063081812fc1461021b578063095ea7b31461023b57806318160ddd14610250575b600080fd5b34801561015c57600080fd5b5061018d61016b366004611eaa565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b3480156101ae57600080fd5b5060408051808201909152600f81526e43727970746f50756e6b732037323160881b60208201525b6040516101999190611ef8565b3480156101ef57600080fd5b506102036101fe366004611f43565b6104c6565b6040516001600160a01b039091168152602001610199565b34801561022757600080fd5b50610203610236366004611f60565b61055b565b61024e610249366004611f79565b61059a565b005b34801561025c57600080fd5b506102656105a9565b604051908152602001610199565b61024e610281366004611fa5565b610639565b61024e610294366004611fa5565b610750565b3480156102a557600080fd5b506102037f000000000000000000000000000000000000000000000000000000000000000081565b3480156102d957600080fd5b506102036102e8366004611f60565b61077d565b3480156102f957600080fd5b50610265610308366004611f43565b6107a2565b34801561031957600080fd5b5061032d610328366004611f43565b6107dd565b6040516101999190611fe6565b34801561034657600080fd5b5061024e610355366004611f60565b61089c565b34801561036657600080fd5b50604080518082019091526005815264cfbe37323160d81b60208201526101d6565b34801561039457600080fd5b5061024e6103a336600461202a565b610a24565b3480156103b457600080fd5b5061024e6103c3366004611f60565b610bea565b3480156103d457600080fd5b5061024e6103e336600461202a565b610c70565b3480156103f457600080fd5b5061024e61040336600461209f565b610daf565b61024e6104163660046120dd565b610e05565b34801561042757600080fd5b506101d6610436366004611f60565b610e59565b34801561044757600080fd5b5061024e610456366004611f60565b610eb4565b34801561046757600080fd5b506101d6610ef2565b34801561047c57600080fd5b5061024e61048b36600461202a565b610f12565b34801561049c57600080fd5b5061018d6104ab36600461217c565b601c52670a5a2e7a000000006008526000526030600c205490565b60405163332599d560e01b81526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063332599d590602401602060405180830381865afa158015610531573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055591906121aa565b92915050565b600081600052673ec412a9852d173d60c11b601c52602060002082018201805460601b6105905763ceea21b66000526004601cfd5b6001015492915050565b6105a5338383610fd1565b5050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610610573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063491906121c7565b905090565b6000818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b03948516949384169381169190828614830261069757826106895763ceea21b66000526004601cfd5b63a11481006000526004601cfd5b846106aa5763ea553b346000526004601cfd5b8560005281600101549250823314863314176106d8576030600c20546106d857634b6e7f186000526004601cfd5b82156106e657600082600101555b85851818905550601c600c8181208054600019019055600084905220805460010163ffffffff8116610720576301336cea6000526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a45b505050565b61075b838383610639565b813b1561074b5761074b83838360405180602001604052806000815250611072565b6000610788826110fe565b90508061079d5763ceea21b66000526004601cfd5b919050565b6000816107b757638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b60606000806107eb846107a2565b905060008167ffffffffffffffff811115610808576108086121e0565b604051908082528060200260200182016040528015610831578160200160208202803683370190505b50905060005b828414610893576000610849826110fe565b9050866001600160a01b0316816001600160a01b03160361088a578183868060010197508151811061087d5761087d6121f6565b6020026020010181815250505b50600101610837565b50949350505050565b60405163332599d560e01b81523360048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063332599d590602401602060405180830381865afa158015610903573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092791906121aa565b9050803b60008190036109c057604051631d85641960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631d856419906024016020604051808303816000875af115801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be91906121aa565b505b6040516390aaf2ff60e01b8152600481018490526001600160a01b038316906390aaf2ff90602401600060405180830381600087803b158015610a0257600080fd5b505af1158015610a16573d6000803e3d6000fd5b5050505061074b3384611126565b60405163332599d560e01b81523360048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063332599d590602401602060405180830381865afa158015610a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aaf91906121aa565b9050803b6000819003610b4857604051631d85641960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631d856419906024016020604051808303816000875af1158015610b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4691906121aa565b505b60005b83811015610be3576000858583818110610b6757610b676121f6565b905060200201359050836001600160a01b03166390aaf2ff826040518263ffffffff1660e01b8152600401610b9e91815260200190565b600060405180830381600087803b158015610bb857600080fd5b505af1158015610bcc573d6000803e3d6000fd5b50505050610bda3382611126565b50600101610b4b565b5050505050565b610bf433826111d4565b6040516322dca8bb60e21b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638b72a2ec90604401600060405180830381600087803b158015610c5c57600080fd5b505af1158015610be3573d6000803e3d6000fd5b60005b8181101561074b576000838383818110610c8f57610c8f6121f6565b6040516323b872dd60e01b815233600482015230602482015260209091029290920135604483018190529250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b158015610d0a57600080fd5b505af1158015610d1e573d6000803e3d6000fd5b5050604051630852cd8d60e31b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506342966c689150602401600060405180830381600087803b158015610d8457600080fd5b505af1158015610d98573d6000803e3d6000fd5b50505050610da63382611126565b50600101610c73565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b610e10858585610639565b833b15610be357610be385858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061107292505050565b60606127108210610e7d5760405163677510db60e11b815260040160405180910390fd5b610e8e610e89836112a2565b6114d3565b604051602001610e9e919061220c565b6040516020818303038152906040529050919050565b6000818152673ec412a9852d173d60c11b601c5260209020810181015460601b15610bf4576040516302a6afa960e11b815260040160405180910390fd5b606060405180606001604052806025815260200161250660259139905090565b60005b8181101561074b576000838383818110610f3157610f316121f6565b905060200201359050610f4433826111d4565b6040516322dca8bb60e21b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638b72a2ec90604401600060405180830381600087803b158015610fac57600080fd5b505af1158015610fc0573d6000803e3d6000fd5b505060019093019250610f15915050565b60001960601c828116925083811693508160005283673ec412a9852d173d60c11b17601c52602060002082018201805482169150816110185763ceea21b66000526004601cfd5b81851485151761103e57816000526030600c205461103e57634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a450505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a084015280156110b9578060c08401826020870160045afa505b60208360a48301601c860160008a5af16110dc573d156110dc573d6000843e3d83fd5b508060e01b8251146110f65763d1a57ed66000526004601cfd5b505050505050565b6000818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690565b6001600160a01b0390911690816111455763ea553b346000526004601cfd5b80600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b1561117a5763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff81166111a6576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b60006111df8261077d565b90505060008181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193821691826112265763ceea21b66000526004601cfd5b82600052816001015480861484871417861517611255576030600c205461125557634b6e7f186000526004601cfd5b801561126357600083600101555b5082189055601c600c208054600019019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b6040516374beb04760e01b815261ffff8216600482015260609082906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906374beb04790602401600060405180830381865afa158015611312573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261133a9190810190612251565b90506113478160186114e1565b9050611385611359826000604a6114f7565b61138060405180606001604052806031815260200161252b6031913961138085604a6114e1565b61155d565b6040516376dfe29760e01b815261ffff841660048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906376dfe29790602401600060405180830381865afa1580156113f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261141b9190810190612251565b9050611426816115b8565b90506114ca61147960405180604001604052806005815260200164696d61676560d81b815250611455856114d3565b60405160200161146591906122fe565b604051602081830303815290604052611949565b6114a56040518060400160405280600a8152602001696174747269627574657360b01b81525084611985565b6040516020016114b6929190612343565b6040516020818303038152906040526119a2565b95945050505050565b6060610555826000806119b5565b60606114f083836000196114f7565b9392505050565b60608351828111611506578092505b838111611511578093505b50818310156114f0575060405182820380825293830193601f19601f820181165b86810151848201528101806115325750600083830160200152603f9091011681016040529392505050565b6040518251601f19906020810182165b858101518482015282018061156d575083518184018360208301165b86810151828201528401806115895750506000910183810160208101929092528352603f011660405292915050565b606060006115e08360405180604001604052806002815260200161016160f51b815250611a9d565b90506000816000815181106115f7576115f76121f6565b6020026020010151600081518110611611576116116121f6565b01602001516001600160f81b03191690506000604d60f81b8214806116435750602360f91b6001600160f81b03198316145b9050606080821561174b57845161165b906002612395565b67ffffffffffffffff811115611673576116736121e0565b6040519080825280602002602001820160405280156116a657816020015b60608152602001906001900390816116915790505b5091506116e6856000815181106116bf576116bf6121f6565b6020026020010151604051806040016040528060018152602001600160fd1b815250611a9d565b9050611728604051806040016040528060048152602001635479706560e01b8152508260008151811061171b5761171b6121f6565b6020026020010151611b48565b8260008151811061173b5761173b6121f6565b60200260200101819052506117f8565b8451611758906001612395565b67ffffffffffffffff811115611770576117706121e0565b6040519080825280602002602001820160405280156117a357816020015b606081526020019060019003908161178e5790505b5091506117d9604051806040016040528060048152602001635479706560e01b8152508660008151811061171b5761171b6121f6565b826000815181106117ec576117ec6121f6565b60200260200101819052505b60006001865161180891906123a8565b60408051808201909152600981526841747472696275746560b81b602082015290915060015b87518110156118725761184d8289838151811061171b5761171b6121f6565b85828151811061185f5761185f6121f6565b602090810291909101015260010161182e565b506118ac6040518060400160405280600f81526020016e105d1d1c9a589d5d194810dbdd5b9d608a1b8152506118a784611ba0565b611b48565b848851815181106118bf576118bf6121f6565b602002602001018190525084156119335761190860405180604001604052806009815260200168536b696e20546f6e6560b81b8152508460018151811061171b5761171b6121f6565b84885160016119179190612395565b81518110611927576119276121f6565b60200260200101819052505b61193c84611be4565b9998505050505050505050565b606061195483611bf7565b61195d83611bf7565b60405160200161196e9291906123bb565b604051602081830303815290604052905092915050565b606061199083611bf7565b8260405160200161196e92919061240f565b606081604051602001610e9e919061245a565b606083518015611a95576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b6003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518252600482019150808210611a2557602001604052613d3d60f01b600384066002048083039190915260008615159091029182900352900382525b509392505050565b60606000611aab8484611c04565b9050601f1960208201600183510160051b81018651838201526001845101845260005b825160608452818114611b135760405182820380825286601f8201165b8b850181015183820152870180611aeb5750600082820160200152603f018616810160405284525b875160209490940193019050818310611ace57505050508091508251611b4157602081019150600281510382525b5092915050565b60606114f0611b796040518060400160405280600a81526020016974726169745f7479706560b01b81525085611949565b6114a56040518060400160405280600581526020016476616c756560d81b81525085611949565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480611bbb575050819003601f19909101908152919050565b6060610555611bf283611cd3565b611cf8565b6060610555826000611d0b565b606082518251818111611ccb576020850194506020840193506020604051019250846001828488010301600060208410611c3d57508286205b601f841660200360031b87515b8951818118831c611c9f578315611c7d5783878c2014611c7d5760018b019a50848b10611c775750611cae565b50611c4a565b858b038952998601996020909801978615611c9f57848b10611c775750611cae565b5060018a019950838a10611c4a575b505060408051601f198189030160051c8152602090970190525050505b505092915050565b606061055582604051806040016040528060018152602001600b60fa1b815250611e13565b606081604051602001610e9e919061248e565b81516040516020019083018215611d2757602282538160010191505b7b5c75303030303031323334353637383961626364656662746e0066726015526b1000000000000004000000005b818514611de55760018501945060ff85511660208110611d9e57816001821b16611d885780845360018401935050611d55565b605c845380600185015360028401935050611d55565b6137006001821b16611dcb578060041c51601d53600f811651601e53601951845260068401935050611d55565b605c84536008810151600185015350600283019250611d55565b50508115611df557602281536001015b6000815260408051601f198184030181526020909201905292915050565b60608251600003611e335750604080516020810190915260008152610555565b600083600081518110611e4857611e486121f6565b602002602001015190506000600190505b8451811015611a95578184868381518110611e7657611e766121f6565b6020026020010151604051602001611e90939291906124c2565b60408051601f198184030181529190529150600101611e59565b600060208284031215611ebc57600080fd5b81356001600160e01b0319811681146114f057600080fd5b60005b83811015611eef578181015183820152602001611ed7565b50506000910152565b6020815260008251806020840152611f17816040850160208701611ed4565b601f01601f19169190910160400192915050565b6001600160a01b0381168114611f4057600080fd5b50565b600060208284031215611f5557600080fd5b81356114f081611f2b565b600060208284031215611f7257600080fd5b5035919050565b60008060408385031215611f8c57600080fd5b8235611f9781611f2b565b946020939093013593505050565b600080600060608486031215611fba57600080fd5b8335611fc581611f2b565b92506020840135611fd581611f2b565b929592945050506040919091013590565b6020808252825182820181905260009190848201906040850190845b8181101561201e57835183529284019291840191600101612002565b50909695505050505050565b6000806020838503121561203d57600080fd5b823567ffffffffffffffff8082111561205557600080fd5b818501915085601f83011261206957600080fd5b81358181111561207857600080fd5b8660208260051b850101111561208d57600080fd5b60209290920196919550909350505050565b600080604083850312156120b257600080fd5b82356120bd81611f2b565b9150602083013580151581146120d257600080fd5b809150509250929050565b6000806000806000608086880312156120f557600080fd5b853561210081611f2b565b9450602086013561211081611f2b565b935060408601359250606086013567ffffffffffffffff8082111561213457600080fd5b818801915088601f83011261214857600080fd5b81358181111561215757600080fd5b89602082850101111561216957600080fd5b9699959850939650602001949392505050565b6000806040838503121561218f57600080fd5b823561219a81611f2b565b915060208301356120d281611f2b565b6000602082840312156121bc57600080fd5b81516114f081611f2b565b6000602082840312156121d957600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161224481601d850160208701611ed4565b91909101601d0192915050565b60006020828403121561226357600080fd5b815167ffffffffffffffff8082111561227b57600080fd5b818401915084601f83011261228f57600080fd5b8151818111156122a1576122a16121e0565b604051601f8201601f19908116603f011681019083821181831017156122c9576122c96121e0565b816040528281528760208487010111156122e257600080fd5b6122f3836020830160208801611ed4565b979650505050505050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000081526000825161233681601a850160208701611ed4565b91909101601a0192915050565b60008351612355818460208801611ed4565b600b60fa1b9083019081528351612373816001840160208801611ed4565b01600101949350505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156105555761055561237f565b818103818111156105555761055561237f565b6000601160f91b80835284516123d8816001860160208901611ed4565b62111d1160e91b60019185019182015284516123fb816004840160208901611ed4565b016004810191909152600501949350505050565b601160f91b8152825160009061242c816001850160208801611ed4565b61111d60f11b600191840191820152835161244e816003840160208801611ed4565b01600301949350505050565b607b60f81b815260008251612476816001850160208701611ed4565b607d60f81b6001939091019283015250600201919050565b605b60f81b8152600082516124aa816001850160208701611ed4565b605d60f81b6001939091019283015250600201919050565b600084516124d4818460208901611ed4565b8451908301906124e8818360208901611ed4565b84519101906124fb818360208801611ed4565b019594505050505056fe68747470733a2f2f6c6963656e73657465726d732e63727970746f70756e6b732e6170702f3c726563742077696474683d223130302522206865696768743d2231303025222066696c6c3d2223363641363730222f3ea2646970667358221220ec69e097faa40b1dd7edff68a2f5c690527e70894098594d1c74088f56d40ba064736f6c63430008170033000000000000000000000000000000000000a6fa31f5fc51c1640aac76866750000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb000000000000000000000000b7f7f6c52f2e2fdb1963eab30438024864c313f600000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b2

Deployed Bytecode

0x60806040526004361061014b5760003560e01c806390aaf2ff116100b6578063b88d4fde1161006f578063b88d4fde14610408578063c87b56dd1461041b578063cbc307021461043b578063df53b5c11461045b578063e4a5016d14610470578063e985e9c51461049057600080fd5b806390aaf2ff1461033a57806395d89b411461035a5780639e88cf42146103885780639f8f573f146103a8578063a14aad90146103c8578063a22cb465146103e857600080fd5b806323b872dd1161010857806323b872dd1461027357806342842e0e146102865780634ed9a045146102995780636352211e146102cd57806370a08231146102ed5780638462151c1461030d57600080fd5b806301ffc9a71461015057806306fdde03146101a257806307f2a9b1146101e3578063081812fc1461021b578063095ea7b31461023b57806318160ddd14610250575b600080fd5b34801561015c57600080fd5b5061018d61016b366004611eaa565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b3480156101ae57600080fd5b5060408051808201909152600f81526e43727970746f50756e6b732037323160881b60208201525b6040516101999190611ef8565b3480156101ef57600080fd5b506102036101fe366004611f43565b6104c6565b6040516001600160a01b039091168152602001610199565b34801561022757600080fd5b50610203610236366004611f60565b61055b565b61024e610249366004611f79565b61059a565b005b34801561025c57600080fd5b506102656105a9565b604051908152602001610199565b61024e610281366004611fa5565b610639565b61024e610294366004611fa5565b610750565b3480156102a557600080fd5b506102037f00000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b281565b3480156102d957600080fd5b506102036102e8366004611f60565b61077d565b3480156102f957600080fd5b50610265610308366004611f43565b6107a2565b34801561031957600080fd5b5061032d610328366004611f43565b6107dd565b6040516101999190611fe6565b34801561034657600080fd5b5061024e610355366004611f60565b61089c565b34801561036657600080fd5b50604080518082019091526005815264cfbe37323160d81b60208201526101d6565b34801561039457600080fd5b5061024e6103a336600461202a565b610a24565b3480156103b457600080fd5b5061024e6103c3366004611f60565b610bea565b3480156103d457600080fd5b5061024e6103e336600461202a565b610c70565b3480156103f457600080fd5b5061024e61040336600461209f565b610daf565b61024e6104163660046120dd565b610e05565b34801561042757600080fd5b506101d6610436366004611f60565b610e59565b34801561044757600080fd5b5061024e610456366004611f60565b610eb4565b34801561046757600080fd5b506101d6610ef2565b34801561047c57600080fd5b5061024e61048b36600461202a565b610f12565b34801561049c57600080fd5b5061018d6104ab36600461217c565b601c52670a5a2e7a000000006008526000526030600c205490565b60405163332599d560e01b81526001600160a01b0382811660048301526000917f000000000000000000000000000000000000a6fa31f5fc51c1640aac768667509091169063332599d590602401602060405180830381865afa158015610531573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055591906121aa565b92915050565b600081600052673ec412a9852d173d60c11b601c52602060002082018201805460601b6105905763ceea21b66000526004601cfd5b6001015492915050565b6105a5338383610fd1565b5050565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb6001600160a01b0316906370a0823190602401602060405180830381865afa158015610610573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063491906121c7565b905090565b6000818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b03948516949384169381169190828614830261069757826106895763ceea21b66000526004601cfd5b63a11481006000526004601cfd5b846106aa5763ea553b346000526004601cfd5b8560005281600101549250823314863314176106d8576030600c20546106d857634b6e7f186000526004601cfd5b82156106e657600082600101555b85851818905550601c600c8181208054600019019055600084905220805460010163ffffffff8116610720576301336cea6000526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a45b505050565b61075b838383610639565b813b1561074b5761074b83838360405180602001604052806000815250611072565b6000610788826110fe565b90508061079d5763ceea21b66000526004601cfd5b919050565b6000816107b757638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b60606000806107eb846107a2565b905060008167ffffffffffffffff811115610808576108086121e0565b604051908082528060200260200182016040528015610831578160200160208202803683370190505b50905060005b828414610893576000610849826110fe565b9050866001600160a01b0316816001600160a01b03160361088a578183868060010197508151811061087d5761087d6121f6565b6020026020010181815250505b50600101610837565b50949350505050565b60405163332599d560e01b81523360048201526000907f000000000000000000000000000000000000a6fa31f5fc51c1640aac768667506001600160a01b03169063332599d590602401602060405180830381865afa158015610903573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092791906121aa565b9050803b60008190036109c057604051631d85641960e01b81523360048201527f000000000000000000000000000000000000a6fa31f5fc51c1640aac768667506001600160a01b031690631d856419906024016020604051808303816000875af115801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be91906121aa565b505b6040516390aaf2ff60e01b8152600481018490526001600160a01b038316906390aaf2ff90602401600060405180830381600087803b158015610a0257600080fd5b505af1158015610a16573d6000803e3d6000fd5b5050505061074b3384611126565b60405163332599d560e01b81523360048201526000907f000000000000000000000000000000000000a6fa31f5fc51c1640aac768667506001600160a01b03169063332599d590602401602060405180830381865afa158015610a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aaf91906121aa565b9050803b6000819003610b4857604051631d85641960e01b81523360048201527f000000000000000000000000000000000000a6fa31f5fc51c1640aac768667506001600160a01b031690631d856419906024016020604051808303816000875af1158015610b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4691906121aa565b505b60005b83811015610be3576000858583818110610b6757610b676121f6565b905060200201359050836001600160a01b03166390aaf2ff826040518263ffffffff1660e01b8152600401610b9e91815260200190565b600060405180830381600087803b158015610bb857600080fd5b505af1158015610bcc573d6000803e3d6000fd5b50505050610bda3382611126565b50600101610b4b565b5050505050565b610bf433826111d4565b6040516322dca8bb60e21b8152336004820152602481018290527f000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb6001600160a01b031690638b72a2ec90604401600060405180830381600087803b158015610c5c57600080fd5b505af1158015610be3573d6000803e3d6000fd5b60005b8181101561074b576000838383818110610c8f57610c8f6121f6565b6040516323b872dd60e01b815233600482015230602482015260209091029290920135604483018190529250506001600160a01b037f000000000000000000000000b7f7f6c52f2e2fdb1963eab30438024864c313f616906323b872dd90606401600060405180830381600087803b158015610d0a57600080fd5b505af1158015610d1e573d6000803e3d6000fd5b5050604051630852cd8d60e31b8152600481018490527f000000000000000000000000b7f7f6c52f2e2fdb1963eab30438024864c313f66001600160a01b031692506342966c689150602401600060405180830381600087803b158015610d8457600080fd5b505af1158015610d98573d6000803e3d6000fd5b50505050610da63382611126565b50600101610c73565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b610e10858585610639565b833b15610be357610be385858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061107292505050565b60606127108210610e7d5760405163677510db60e11b815260040160405180910390fd5b610e8e610e89836112a2565b6114d3565b604051602001610e9e919061220c565b6040516020818303038152906040529050919050565b6000818152673ec412a9852d173d60c11b601c5260209020810181015460601b15610bf4576040516302a6afa960e11b815260040160405180910390fd5b606060405180606001604052806025815260200161250660259139905090565b60005b8181101561074b576000838383818110610f3157610f316121f6565b905060200201359050610f4433826111d4565b6040516322dca8bb60e21b8152336004820152602481018290527f000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb6001600160a01b031690638b72a2ec90604401600060405180830381600087803b158015610fac57600080fd5b505af1158015610fc0573d6000803e3d6000fd5b505060019093019250610f15915050565b60001960601c828116925083811693508160005283673ec412a9852d173d60c11b17601c52602060002082018201805482169150816110185763ceea21b66000526004601cfd5b81851485151761103e57816000526030600c205461103e57634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a450505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a084015280156110b9578060c08401826020870160045afa505b60208360a48301601c860160008a5af16110dc573d156110dc573d6000843e3d83fd5b508060e01b8251146110f65763d1a57ed66000526004601cfd5b505050505050565b6000818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690565b6001600160a01b0390911690816111455763ea553b346000526004601cfd5b80600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b1561117a5763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff81166111a6576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b60006111df8261077d565b90505060008181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193821691826112265763ceea21b66000526004601cfd5b82600052816001015480861484871417861517611255576030600c205461125557634b6e7f186000526004601cfd5b801561126357600083600101555b5082189055601c600c208054600019019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b6040516374beb04760e01b815261ffff8216600482015260609082906000907f00000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b26001600160a01b0316906374beb04790602401600060405180830381865afa158015611312573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261133a9190810190612251565b90506113478160186114e1565b9050611385611359826000604a6114f7565b61138060405180606001604052806031815260200161252b6031913961138085604a6114e1565b61155d565b6040516376dfe29760e01b815261ffff841660048201529091506000906001600160a01b037f00000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b216906376dfe29790602401600060405180830381865afa1580156113f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261141b9190810190612251565b9050611426816115b8565b90506114ca61147960405180604001604052806005815260200164696d61676560d81b815250611455856114d3565b60405160200161146591906122fe565b604051602081830303815290604052611949565b6114a56040518060400160405280600a8152602001696174747269627574657360b01b81525084611985565b6040516020016114b6929190612343565b6040516020818303038152906040526119a2565b95945050505050565b6060610555826000806119b5565b60606114f083836000196114f7565b9392505050565b60608351828111611506578092505b838111611511578093505b50818310156114f0575060405182820380825293830193601f19601f820181165b86810151848201528101806115325750600083830160200152603f9091011681016040529392505050565b6040518251601f19906020810182165b858101518482015282018061156d575083518184018360208301165b86810151828201528401806115895750506000910183810160208101929092528352603f011660405292915050565b606060006115e08360405180604001604052806002815260200161016160f51b815250611a9d565b90506000816000815181106115f7576115f76121f6565b6020026020010151600081518110611611576116116121f6565b01602001516001600160f81b03191690506000604d60f81b8214806116435750602360f91b6001600160f81b03198316145b9050606080821561174b57845161165b906002612395565b67ffffffffffffffff811115611673576116736121e0565b6040519080825280602002602001820160405280156116a657816020015b60608152602001906001900390816116915790505b5091506116e6856000815181106116bf576116bf6121f6565b6020026020010151604051806040016040528060018152602001600160fd1b815250611a9d565b9050611728604051806040016040528060048152602001635479706560e01b8152508260008151811061171b5761171b6121f6565b6020026020010151611b48565b8260008151811061173b5761173b6121f6565b60200260200101819052506117f8565b8451611758906001612395565b67ffffffffffffffff811115611770576117706121e0565b6040519080825280602002602001820160405280156117a357816020015b606081526020019060019003908161178e5790505b5091506117d9604051806040016040528060048152602001635479706560e01b8152508660008151811061171b5761171b6121f6565b826000815181106117ec576117ec6121f6565b60200260200101819052505b60006001865161180891906123a8565b60408051808201909152600981526841747472696275746560b81b602082015290915060015b87518110156118725761184d8289838151811061171b5761171b6121f6565b85828151811061185f5761185f6121f6565b602090810291909101015260010161182e565b506118ac6040518060400160405280600f81526020016e105d1d1c9a589d5d194810dbdd5b9d608a1b8152506118a784611ba0565b611b48565b848851815181106118bf576118bf6121f6565b602002602001018190525084156119335761190860405180604001604052806009815260200168536b696e20546f6e6560b81b8152508460018151811061171b5761171b6121f6565b84885160016119179190612395565b81518110611927576119276121f6565b60200260200101819052505b61193c84611be4565b9998505050505050505050565b606061195483611bf7565b61195d83611bf7565b60405160200161196e9291906123bb565b604051602081830303815290604052905092915050565b606061199083611bf7565b8260405160200161196e92919061240f565b606081604051602001610e9e919061245a565b606083518015611a95576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b6003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518252600482019150808210611a2557602001604052613d3d60f01b600384066002048083039190915260008615159091029182900352900382525b509392505050565b60606000611aab8484611c04565b9050601f1960208201600183510160051b81018651838201526001845101845260005b825160608452818114611b135760405182820380825286601f8201165b8b850181015183820152870180611aeb5750600082820160200152603f018616810160405284525b875160209490940193019050818310611ace57505050508091508251611b4157602081019150600281510382525b5092915050565b60606114f0611b796040518060400160405280600a81526020016974726169745f7479706560b01b81525085611949565b6114a56040518060400160405280600581526020016476616c756560d81b81525085611949565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480611bbb575050819003601f19909101908152919050565b6060610555611bf283611cd3565b611cf8565b6060610555826000611d0b565b606082518251818111611ccb576020850194506020840193506020604051019250846001828488010301600060208410611c3d57508286205b601f841660200360031b87515b8951818118831c611c9f578315611c7d5783878c2014611c7d5760018b019a50848b10611c775750611cae565b50611c4a565b858b038952998601996020909801978615611c9f57848b10611c775750611cae565b5060018a019950838a10611c4a575b505060408051601f198189030160051c8152602090970190525050505b505092915050565b606061055582604051806040016040528060018152602001600b60fa1b815250611e13565b606081604051602001610e9e919061248e565b81516040516020019083018215611d2757602282538160010191505b7b5c75303030303031323334353637383961626364656662746e0066726015526b1000000000000004000000005b818514611de55760018501945060ff85511660208110611d9e57816001821b16611d885780845360018401935050611d55565b605c845380600185015360028401935050611d55565b6137006001821b16611dcb578060041c51601d53600f811651601e53601951845260068401935050611d55565b605c84536008810151600185015350600283019250611d55565b50508115611df557602281536001015b6000815260408051601f198184030181526020909201905292915050565b60608251600003611e335750604080516020810190915260008152610555565b600083600081518110611e4857611e486121f6565b602002602001015190506000600190505b8451811015611a95578184868381518110611e7657611e766121f6565b6020026020010151604051602001611e90939291906124c2565b60408051601f198184030181529190529150600101611e59565b600060208284031215611ebc57600080fd5b81356001600160e01b0319811681146114f057600080fd5b60005b83811015611eef578181015183820152602001611ed7565b50506000910152565b6020815260008251806020840152611f17816040850160208701611ed4565b601f01601f19169190910160400192915050565b6001600160a01b0381168114611f4057600080fd5b50565b600060208284031215611f5557600080fd5b81356114f081611f2b565b600060208284031215611f7257600080fd5b5035919050565b60008060408385031215611f8c57600080fd5b8235611f9781611f2b565b946020939093013593505050565b600080600060608486031215611fba57600080fd5b8335611fc581611f2b565b92506020840135611fd581611f2b565b929592945050506040919091013590565b6020808252825182820181905260009190848201906040850190845b8181101561201e57835183529284019291840191600101612002565b50909695505050505050565b6000806020838503121561203d57600080fd5b823567ffffffffffffffff8082111561205557600080fd5b818501915085601f83011261206957600080fd5b81358181111561207857600080fd5b8660208260051b850101111561208d57600080fd5b60209290920196919550909350505050565b600080604083850312156120b257600080fd5b82356120bd81611f2b565b9150602083013580151581146120d257600080fd5b809150509250929050565b6000806000806000608086880312156120f557600080fd5b853561210081611f2b565b9450602086013561211081611f2b565b935060408601359250606086013567ffffffffffffffff8082111561213457600080fd5b818801915088601f83011261214857600080fd5b81358181111561215757600080fd5b89602082850101111561216957600080fd5b9699959850939650602001949392505050565b6000806040838503121561218f57600080fd5b823561219a81611f2b565b915060208301356120d281611f2b565b6000602082840312156121bc57600080fd5b81516114f081611f2b565b6000602082840312156121d957600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161224481601d850160208701611ed4565b91909101601d0192915050565b60006020828403121561226357600080fd5b815167ffffffffffffffff8082111561227b57600080fd5b818401915084601f83011261228f57600080fd5b8151818111156122a1576122a16121e0565b604051601f8201601f19908116603f011681019083821181831017156122c9576122c96121e0565b816040528281528760208487010111156122e257600080fd5b6122f3836020830160208801611ed4565b979650505050505050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000081526000825161233681601a850160208701611ed4565b91909101601a0192915050565b60008351612355818460208801611ed4565b600b60fa1b9083019081528351612373816001840160208801611ed4565b01600101949350505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156105555761055561237f565b818103818111156105555761055561237f565b6000601160f91b80835284516123d8816001860160208901611ed4565b62111d1160e91b60019185019182015284516123fb816004840160208901611ed4565b016004810191909152600501949350505050565b601160f91b8152825160009061242c816001850160208801611ed4565b61111d60f11b600191840191820152835161244e816003840160208801611ed4565b01600301949350505050565b607b60f81b815260008251612476816001850160208701611ed4565b607d60f81b6001939091019283015250600201919050565b605b60f81b8152600082516124aa816001850160208701611ed4565b605d60f81b6001939091019283015250600201919050565b600084516124d4818460208901611ed4565b8451908301906124e8818360208901611ed4565b84519101906124fb818360208801611ed4565b019594505050505056fe68747470733a2f2f6c6963656e73657465726d732e63727970746f70756e6b732e6170702f3c726563742077696474683d223130302522206865696768743d2231303025222066696c6c3d2223363641363730222f3ea2646970667358221220ec69e097faa40b1dd7edff68a2f5c690527e70894098594d1c74088f56d40ba064736f6c63430008170033

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

000000000000000000000000000000000000a6fa31f5fc51c1640aac76866750000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb000000000000000000000000b7f7f6c52f2e2fdb1963eab30438024864c313f600000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b2

-----Decoded View---------------
Arg [0] : stashFactory (address): 0x000000000000A6fA31F5fC51c1640aAc76866750
Arg [1] : cryptoPunks (address): 0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB
Arg [2] : legacyWrapper (address): 0xb7F7F6C52F2e2fdb1963Eab30438024864c313F6
Arg [3] : _punksMetadata (address): 0x16F5A35647D6F03D5D3da7b35409D65ba03aF3B2

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000000a6fa31f5fc51c1640aac76866750
Arg [1] : 000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb
Arg [2] : 000000000000000000000000b7f7f6c52f2e2fdb1963eab30438024864c313f6
Arg [3] : 00000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b2


Deployed Bytecode Sourcemap

582:6502:4:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14979:380:1;;;;;;;;;;-1:-1:-1;14979:380:1;;;;;:::i;:::-;15292:10;15157:3;15153:21;;;;15286:17;;;15311:10;15305:17;;15283:40;15331:10;15325:17;;;15280:63;;14979:380;;;;470:14:13;;463:22;445:41;;433:2;418:18;14979:380:1;;;;;;;;1189:102:4;;;;;;;;;;-1:-1:-1;1260:24:4;;;;;;;;;;;;-1:-1:-1;;;1260:24:4;;;;1189:102;;;;;;;:::i;5579:131::-;;;;;;;;;;-1:-1:-1;5579:131:4;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1705:32:13;;;1687:51;;1675:2;1660:18;5579:131:4;1541:203:13;8099:532:1;;;;;;;;;;-1:-1:-1;8099:532:1;;;;;:::i;:::-;;:::i;8925:119::-;;;;;;:::i;:::-;;:::i;:::-;;6965:117:4;;;;;;;;;;;;;:::i;:::-;;;2400:25:13;;;2388:2;2373:18;6965:117:4;2254:177:13;10748:3001:1;;;;;;:::i;:::-;;:::i;13820:198::-;;;;;;:::i;:::-;;:::i;570:44:5:-;;;;;;;;;;;;;;;6957:332:1;;;;;;;;;;-1:-1:-1;6957:332:1;;;;;:::i;:::-;;:::i;7433:533::-;;;;;;;;;;-1:-1:-1;7433:533:1;;;;;:::i;:::-;;:::i;6048:549:4:-;;;;;;;;;;-1:-1:-1;6048:549:4;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;2163:380::-;;;;;;;;;;-1:-1:-1;2163:380:4;;;;;:::i;:::-;;:::i;1297:101::-;;;;;;;;;;-1:-1:-1;1370:21:4;;;;;;;;;;;;-1:-1:-1;;;1370:21:4;;;;1297:101;;2816:524;;;;;;;;;;-1:-1:-1;2816:524:4;;;;;:::i;:::-;;:::i;3535:151::-;;;;;;;;;;-1:-1:-1;3535:151:4;;;;;:::i;:::-;;:::i;4394:365::-;;;;;;;;;;-1:-1:-1;4394:365:4;;;;;:::i;:::-;;:::i;9667:726:1:-;;;;;;;;;;-1:-1:-1;9667:726:1;;;;;:::i;:::-;;:::i;14521:249::-;;;;;;:::i;:::-;;:::i;1535:373:4:-;;;;;;;;;;-1:-1:-1;1535:373:4;;;;;:::i;:::-;;:::i;5274:167::-;;;;;;;;;;-1:-1:-1;5274:167:4;;;;;:::i;:::-;;:::i;1404:125::-;;;;;;;;;;;;;:::i;3899:295::-;;;;;;;;;;-1:-1:-1;3899:295:4;;;;;:::i;:::-;;:::i;9135:392:1:-;;;;;;;;;;-1:-1:-1;9135:392:1;;;;;:::i;:::-;9355:4;9348:22;9396:31;9390:4;9383:45;9255:11;9441:19;9505:4;9499;9489:21;9483:28;;9135:392;5579:131:4;5668:35;;-1:-1:-1;;;5668:35:4;;-1:-1:-1;;;;;1705:32:13;;;5668:35:4;;;1687:51:13;5642:7:4;;5668:13;:29;;;;;;1660:18:13;;5668:35:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5661:42;5579:131;-1:-1:-1;;5579:131:4:o;8099:532:1:-;8161:14;8266:2;8260:4;8253:16;-1:-1:-1;;;8289:4:1;8282:38;8386:4;8380;8370:21;8366:2;8362:30;8358:2;8354:39;8430:13;8424:20;8420:2;8416:29;8406:158;;8478:10;8472:4;8465:24;8545:4;8539;8532:18;8406:158;8597:1;8593:21;8587:28;;8099:532;-1:-1:-1;;8099:532:1:o;8925:119::-;9004:33;9013:10;9025:7;9034:2;9004:8;:33::i;:::-;8925:119;;:::o;6965:117:4:-;7037:37;;-1:-1:-1;;;7037:37:4;;7068:4;7037:37;;;1687:51:13;7011:7:4;;7037:12;-1:-1:-1;;;;;7037:22:4;;;;1660:18:13;;7037:37:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7030:44;;6965:117;:::o;10748:3001:1:-;11025:1;11169:16;;;-1:-1:-1;;;11240:8:1;11211:38;11205:4;11198:52;11316:4;11300:21;;11292:30;;11284:39;;11359:20;;-1:-1:-1;;;;;11049:25:1;;;;11093:23;;;;11405:36;;;11284:39;11544:15;;;11533:27;;11523:328;;11590:5;11580:146;;11632:10;11626:4;11619:24;11703:4;11697;11690:18;11580:146;11756:10;11750:4;11743:24;11832:4;11826;11819:18;11523:328;11925:2;11915:135;;11960:10;11954:4;11947:24;12031:4;12025;12018:18;11915:135;12153:4;12147;12140:18;12211:13;12208:1;12204:21;12198:28;12175:51;;12361:15;12351:8;12348:29;12341:4;12331:8;12328:18;12325:53;12315:288;;12434:4;12428;12418:21;12412:28;12402:183;;12481:10;12475:4;12468:24;12558:4;12552;12545:18;12402:183;12678:15;12675:55;;;12726:1;12710:13;12707:1;12703:21;12696:32;12675:55;12842:13;;;12821:35;12799:58;;-1:-1:-1;12975:4:1;12969;12959:21;;;13025:22;;-1:-1:-1;;13021:30:1;12997:55;;-1:-1:-1;13143:16:1;;;13197:21;13266:20;;13049:1;13262:28;13342:20;13317:46;;13307:192;;13400:10;13394:4;13387:24;13476:4;13470;13463:18;13307:192;13516:42;;13687:2;13683;13677:4;13650:25;13644:4;13632:10;13627:63;13709:33;10748:3001;;;:::o;13820:198::-;13917:26;13930:4;13936:2;13940;13917:12;:26::i;:::-;36962:14;;13953:58;;;13971:40;13994:4;14000:2;14004;13971:40;;;;;;;;;;;;:22;:40::i;6957:332::-;7015:14;7050:12;7059:2;7050:8;:12::i;:::-;7041:21;;7148:6;7138:135;;7187:10;7181:4;7174:24;7254:4;7248;7241:18;7138:135;6957:332;;;:::o;7433:533::-;7496:14;7656:5;7646:143;;7694:10;7688:4;7681:24;7770:4;7764;7757:18;7646:143;-1:-1:-1;;;7809:4:1;7802:38;7866:5;7860:4;7853:19;7929:20;7921:4;7915;7905:21;7899:28;7895:55;7885:65;;7433:533;;;:::o;6048:549:4:-;6109:16;6161:19;6194:22;6219:16;6229:5;6219:9;:16::i;:::-;6194:41;;6249:25;6291:14;6277:29;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6277:29:4;;6249:57;;6326:9;6321:231;6356:14;6341:11;:29;6321:231;;6395:18;6416:11;6425:1;6416:8;:11::i;:::-;6395:32;;6463:5;-1:-1:-1;;;;;6449:19:4;:10;-1:-1:-1;;;;;6449:19:4;;6445:93;;6518:1;6492:8;6501:13;;;;;;6492:23;;;;;;;;:::i;:::-;;;;;;:27;;;;;6445:93;-1:-1:-1;6372:3:4;;6321:231;;;-1:-1:-1;6572:8:4;6048:549;-1:-1:-1;;;;6048:549:4:o;2163:380::-;2235:41;;-1:-1:-1;;;2235:41:4;;2265:10;2235:41;;;1687:51:13;2219:13:4;;2235;-1:-1:-1;;;;;2235:29:4;;;;1660:18:13;;2235:41:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2219:57;-1:-1:-1;2340:18:4;;2287:12;2382:9;;;2378:77;;2407:37;;-1:-1:-1;;;2407:37:4;;2433:10;2407:37;;;1687:51:13;2407:13:4;-1:-1:-1;;;;;2407:25:4;;;;1660:18:13;;2407:37:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;2378:77;2465:33;;-1:-1:-1;;;2465:33:4;;;;;2400:25:13;;;-1:-1:-1;;;;;2465:22:4;;;;;2373:18:13;;2465:33:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2508:28;2514:10;2526:9;2508:5;:28::i;2816:524::-;2906:41;;-1:-1:-1;;;2906:41:4;;2936:10;2906:41;;;1687:51:13;2890:13:4;;2906;-1:-1:-1;;;;;2906:29:4;;;;1660:18:13;;2906:41:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2890:57;-1:-1:-1;3011:18:4;;2958:12;3053:9;;;3049:77;;3078:37;;-1:-1:-1;;;3078:37:4;;3104:10;3078:37;;;1687:51:13;3078:13:4;-1:-1:-1;;;;;3078:25:4;;;;1660:18:13;;3078:37:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;3049:77;3141:9;3136:198;3156:22;;;3136:198;;;3199:17;3219:11;;3231:1;3219:14;;;;;;;:::i;:::-;;;;;;;3199:34;;3255:5;-1:-1:-1;;;;;3248:22:4;;3271:9;3248:33;;;;;;;;;;;;;2400:25:13;;2388:2;2373:18;;2254:177;3248:33:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3295:28;3301:10;3313:9;3295:5;:28::i;:::-;-1:-1:-1;3180:3:4;;3136:198;;;;2880:460;;2816:524;;:::o;3535:151::-;3593:28;3599:10;3611:9;3593:5;:28::i;:::-;3631:48;;-1:-1:-1;;;3631:48:4;;3657:10;3631:48;;;7025:51:13;7092:18;;;7085:34;;;3631:12:4;-1:-1:-1;;;;;3631:25:4;;;;6998:18:13;;3631:48:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4394:365;4485:9;4480:273;4500:22;;;4480:273;;;4543:17;4563:11;;4575:1;4563:14;;;;;;;:::i;:::-;4591:65;;-1:-1:-1;;;4591:65:4;;4619:10;4591:65;;;7370:34:13;4639:4:4;7420:18:13;;;7413:43;4563:14:4;;;;;;;;;7472:18:13;;;7465:34;;;4563:14:4;-1:-1:-1;;;;;;;4591:14:4;:27;;;;7305:18:13;;4591:65:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4670:30:4;;-1:-1:-1;;;4670:30:4;;;;;2400:25:13;;;4670:14:4;-1:-1:-1;;;;;4670:19:4;;-1:-1:-1;4670:19:4;;-1:-1:-1;2373:18:13;;4670:30:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4714:28;4720:10;4732:9;4714:5;:28::i;:::-;-1:-1:-1;4524:3:4;;4480:273;;9667:726:1;9882:10;9875:18;9868:26;9854:40;;9991:8;9985:4;9978:22;10026:31;10020:4;10013:45;10084:8;10078:4;10071:22;10136:10;10129:4;10123;10113:21;10106:41;10221:10;10215:4;10208:24;10366:8;10362:2;10358:17;10354:2;10350:26;10340:8;10305:33;10299:4;10293;10288:89;9667:726;;:::o;14521:249::-;14667:26;14680:4;14686:2;14690;14667:12;:26::i;:::-;36962:14;;14703:60;;;14721:42;14744:4;14750:2;14754;14758:4;;14721:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14721:22:1;;-1:-1:-1;;;14721:42:1:i;1535:373:4:-;1600:13;1739:5;1728:7;:16;1724:73;;1767:19;;-1:-1:-1;;;1767:19:4;;;;;;;;;;;1724:73;1860:40;1880:18;1890:7;1880:9;:18::i;:::-;1860:13;:40::i;:::-;1813:88;;;;;;;;:::i;:::-;;;;;;;;;;;;;1806:95;;1535:373;;;:::o;5274:167::-;15751:11:1;15840:16;;;-1:-1:-1;;;15876:4:1;15869:38;15990:4;15974:21;;15966:30;;15958:39;;15952:46;15948:2;15944:55;15937:63;5332:44:4;;5363:13;;-1:-1:-1;;;5363:13:4;;;;;;;;;;;1404:125;1451:13;1476:46;;;;;;;;;;;;;;;;;;;1404:125;:::o;3899:295::-;3980:9;3975:213;3995:22;;;3975:213;;;4038:17;4058:11;;4070:1;4058:14;;;;;;;:::i;:::-;;;;;;;4038:34;;4087:28;4093:10;4105:9;4087:5;:28::i;:::-;4129:48;;-1:-1:-1;;;4129:48:4;;4155:10;4129:48;;;7025:51:13;7092:18;;;7085:34;;;4129:12:4;-1:-1:-1;;;;;4129:25:4;;;;6998:18:13;;4129:48:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4019:3:4;;;;;-1:-1:-1;3975:213:4;;-1:-1:-1;;3975:213:4;27519:1442:1;27702:1;27698:6;27694:2;27690:15;27749:7;27733:14;27729:28;27718:39;;27796:2;27780:14;27776:23;27770:29;;27869:2;27863:4;27856:16;27927:2;-1:-1:-1;;;27898:32:1;27892:4;27885:46;27997:4;27991;27981:21;27977:2;27973:30;27969:2;27965:39;28056:13;28050:20;28034:14;28030:41;28017:54;;28145:5;28135:134;;28183:10;28177:4;28170:24;28250:4;28244;28237:18;28135:134;28452:5;28448:2;28445:13;28440:2;28433:10;28430:29;28420:280;;28492:5;28486:4;28479:19;28547:4;28541;28531:21;28525:28;28515:171;;28590:10;28584:4;28577:24;28663:4;28657;28650:18;28515:171;28794:1;28790:21;28783:38;;;28942:2;28813:7;28926:5;28899:25;28893:4;28881:10;28876:69;;27519:1442;;;:::o;37183:1370::-;37420:4;37414:11;37470:10;37503:24;37500:1;37493:35;37562:8;37555:4;37552:1;37548:12;37541:30;37670:4;37666:2;37662:13;37658:2;37654:22;37647:4;37644:1;37640:12;37633:44;37711:2;37704:4;37701:1;37697:12;37690:24;37748:4;37741;37738:1;37734:12;37727:26;37781:4;37775:11;37820:1;37813:4;37810:1;37806:12;37799:23;37838:1;37835:71;;;37901:1;37894:4;37891:1;37887:12;37884:1;37877:4;37871;37867:15;37864:1;37857:5;37846:57;37842:62;37835:71;38022:4;38019:1;38012:4;38009:1;38005:12;37998:4;37995:1;37991:12;37988:1;37984:2;37977:5;37972:55;37962:313;;38050:16;38047:214;;;38178:16;38172:4;38169:1;38154:41;38226:16;38223:1;38216:27;38047:214;37962:313;38371:24;38366:3;38362:34;38358:1;38352:8;38349:48;38339:198;;38430:10;38424:4;38417:24;38518:4;38512;38505:18;38339:198;;;37183:1370;;;;:::o;16152:323::-;16213:14;16305:16;;;-1:-1:-1;;;16341:4:1;16334:38;16449:4;16433:21;;16425:30;;16417:39;16411:46;-1:-1:-1;;;;;16395:64:1;;16152:323::o;19724:1682::-;-1:-1:-1;;;;;19952:20:1;;;;;20036:135;;20081:10;20075:4;20068:24;20152:4;20146;20139:18;20036:135;20237:2;20231:4;20224:16;-1:-1:-1;;;20260:4:1;20253:38;20357:4;20351;20341:21;20337:2;20333:30;20329:2;20325:39;20406:13;20400:20;20495:15;20491:2;20487:24;20484:146;;;20543:10;20537:4;20530:24;20611:4;20605;20598:18;20484:146;20703:23;;20681:46;;20816:4;20809:16;;;20877:4;20871;20861:21;20928:18;;20948:1;20924:26;21000:20;20977:44;;20967:190;;21058:10;21052:4;21045:24;21134:4;21128;21121:18;20967:190;21174:38;;21338:2;21334;21331:1;21304:25;21331:1;21286:10;21281:60;8925:119;;:::o;22812:2127::-;22878:13;22894:11;22902:2;22894:7;:11::i;:::-;22878:27;;-1:-1:-1;23160:4:1;23153:16;;;-1:-1:-1;;;;;23080:20:1;;;-1:-1:-1;;;23195:32:1;;23189:4;23182:46;23294:4;23278:21;;;23270:30;;23262:39;;23337:20;;23080;;23460:33;;;;23557:134;;23605:10;23599:4;23592:24;23672:4;23666;23659:18;23557:134;23785:5;23779:4;23772:19;23844:13;23841:1;23837:21;23831:28;24076:15;24072:2;24069:23;24061:5;24057:2;24054:13;24051:42;24046:2;24039:10;24036:58;24026:293;;24150:4;24144;24134:21;24128:28;24118:183;;24197:10;24191:4;24184:24;24274:4;24268;24261:18;24118:183;24394:15;24391:55;;;24442:1;24426:13;24423:1;24419:21;24412:32;24391:55;-1:-1:-1;24527:27:1;;24505:50;;24670:4;24664;24654:21;24716:18;;-1:-1:-1;;24712:26:1;24692:47;;24868:2;-1:-1:-1;24548:5:1;24831:25;-1:-1:-1;24813:10:1;24808:63;10748:3001;;;:::o;954:819:5:-;1108:34;;-1:-1:-1;;;1108:34:5;;8140:6:13;8128:19;;1108:34:5;;;8110:38:13;1013:13:5;;1064:7;;1038:16;;1108:10;-1:-1:-1;;;;;1108:23:5;;;;8083:18:13;;1108:34:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1108:34:5;;;;;;;;;;;;:::i;:::-;1082:60;;1164:30;1180:9;1191:2;1164:15;:30::i;:::-;1152:42;;1217:141;1247:33;1263:9;1274:1;1277:2;1247:15;:33::i;:::-;1282:66;1299:16;;;;;;;;;;;;;;;;;1317:30;1333:9;1344:2;1317:15;:30::i;:::-;1282:16;:66::i;1217:141::-;1396:36;;-1:-1:-1;;;1396:36:5;;8140:6:13;8128:19;;1396:36:5;;;8110:38:13;1205:153:5;;-1:-1:-1;1369:24:5;;-1:-1:-1;;;;;1396:10:5;:25;;;;8083:18:13;;1396:36:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1396:36:5;;;;;;;;;;;;:::i;:::-;1369:63;;1456:32;1477:10;1456:20;:32::i;:::-;1443:45;;1505:261;1561:100;;;;;;;;;;;;;;-1:-1:-1;;;1561:100:5;;;1628:31;1648:9;1628:13;:31::i;:::-;1584:76;;;;;;;;:::i;:::-;;;;;;;;;;;;;1561:13;:100::i;:::-;1700:42;;;;;;;;;;;;;;-1:-1:-1;;;1700:42:5;;;1731:10;1700:16;:42::i;:::-;1530:226;;;;;;;;;:::i;:::-;;;;;;;;;;;;;1505:11;:261::i;:::-;1498:268;954:819;-1:-1:-1;;;;;954:819:5:o;3414:132:2:-;3472:20;3513:26;3520:4;3526:5;3533;3513:6;:26::i;31638:194:3:-;31738:20;31783:42;31789:7;31798:5;-1:-1:-1;;31783:5:3;:42::i;:::-;31774:51;31638:194;-1:-1:-1;;;31638:194:3:o;30204:1307::-;30317:20;30446:7;30440:14;30495:3;30480:13;30477:22;30467:58;;30510:13;30503:20;;30467:58;30566:5;30551:13;30548:24;30538:62;;30585:13;30576:22;;30538:62;;30626:3;30619:5;30616:14;30613:882;;;-1:-1:-1;30665:4:3;30659:11;30707:15;;;30739:28;;;30795:19;;;;-1:-1:-1;;30844:4:3;30954:23;;30950:31;;30935:237;31040:15;;;31034:22;31018:14;;;31011:46;31083:9;;31132:22;30935:237;31132:22;-1:-1:-1;31288:1:3;31250:36;;;31266:4;31250:36;31243:47;31470:4;31452:23;;;31448:31;31436:44;;31430:4;31423:58;30204:1307;;;;;:::o;36854:1365::-;37100:4;37094:11;37133:8;;-1:-1:-1;;37062:9:3;37241:4;37228:18;;37224:26;;37209:210;37305:9;;;37299:16;37283:14;;;37276:40;37338:9;;37383:22;37209:210;37383:22;37213:39;37453:1;37447:8;37494:7;37486:6;37482:20;37609:1;37602:4;37593:7;37589:18;37585:26;37570:210;37666:9;;;37660:16;37644:14;;;37637:40;37699:9;;37744:22;37570:210;37744:22;-1:-1:-1;;37969:1:3;37812:21;;37858:35;;;37874:4;37858:35;;37956:15;;;;38018:27;;38183:15;;38179:23;38173:4;38166:37;37866:6;36854:1365;-1:-1:-1;;36854:1365:3:o;2011:2047:5:-;2090:20;2122:32;2157:41;2173:10;2185:12;;;;;;;;;;;;;-1:-1:-1;;;2185:12:5;;;2157:15;:41::i;:::-;2122:76;;2208:16;2233;2250:1;2233:19;;;;;;;;:::i;:::-;;;;;;;2254:1;2227:29;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;;2227:29:5;;-1:-1:-1;2349:12:5;-1:-1:-1;;;2364:16:5;;;:36;;-1:-1:-1;;;;;;;;;;2384:16:5;;;2364:36;2349:51;;2410:31;2483:38;2535:7;2531:524;;;2682:23;;:27;;2708:1;2682:27;:::i;:::-;2669:41;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2651:59;;2749:41;2765:16;2782:1;2765:19;;;;;;;;:::i;:::-;;;;;;;2749:41;;;;;;;;;;;;;-1:-1:-1;;;2749:41:5;;;:15;:41::i;:::-;2724:66;;2825:50;;;;;;;;;;;;;;-1:-1:-1;;;2825:50:5;;;2849:22;2872:1;2849:25;;;;;;;;:::i;:::-;;;;;;;2825:15;:50::i;:::-;2804:15;2820:1;2804:18;;;;;;;;:::i;:::-;;;;;;:71;;;;2531:524;;;2937:23;;:27;;2963:1;2937:27;:::i;:::-;2924:41;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2906:59;;3000:44;;;;;;;;;;;;;;-1:-1:-1;;;3000:44:5;;;3024:16;3041:1;3024:19;;;;;;;;:::i;3000:44::-;2979:15;2995:1;2979:18;;;;;;;;:::i;:::-;;;;;;:65;;;;2531:524;3152:13;3194:1;3168:16;:23;:27;;;;:::i;:::-;3322:33;;;;;;;;;;;;-1:-1:-1;;;3322:33:5;;;;3152:43;;-1:-1:-1;3462:1:5;3445:143;3469:16;:23;3465:1;:27;3445:143;;;3534:43;3550:5;3557:16;3574:1;3557:19;;;;;;;;:::i;3534:43::-;3513:15;3529:1;3513:18;;;;;;;;:::i;:::-;;;;;;;;;;:64;3494:3;;3445:143;;;;3689:61;;;;;;;;;;;;;;-1:-1:-1;;;3689:61:5;;;3724:25;3743:5;3724:18;:25::i;:::-;3689:15;:61::i;:::-;3646:15;3662:16;:23;3646:40;;;;;;;;:::i;:::-;;;;;;:104;;;;3765:7;3761:186;;;3881:55;;;;;;;;;;;;;;-1:-1:-1;;;3881:55:5;;;3910:22;3933:1;3910:25;;;;;;;;:::i;3881:55::-;3834:15;3850:16;:23;3876:1;3850:27;;;;:::i;:::-;3834:44;;;;;;;;:::i;:::-;;;;;;:102;;;;3761:186;4022:29;4035:15;4022:12;:29::i;:::-;4015:36;2011:2047;-1:-1:-1;;;;;;;;;2011:2047:5:o;1099:190:0:-;1181:13;1232:17;:4;:15;:17::i;:::-;1258:18;:5;:16;:18::i;:::-;1213:69;;;;;;;;;:::i;:::-;;;;;;;;;;;;;1206:76;;1099:190;;;;:::o;1667:180::-;1755:13;1806:17;:4;:15;:17::i;:::-;1831:8;1787:53;;;;;;;;;:::i;361:129::-;421:13;472:5;453:30;;;;;;;;:::i;722:2557:2:-;835:20;961:4;955:11;983:10;980:2283;;;1183:1;1179;1167:10;1163:18;1159:26;1156:1;1152:34;1294:4;1288:11;1278:21;;1664:34;1658:4;1651:48;1791:6;1780:8;1773:16;1769:29;1733:34;1729:70;1723:4;1716:84;1906:4;1898:6;1894:17;1948:13;1943:3;1939:23;2038:623;2090:1;2084:4;2080:12;2072:20;;2152:4;2146:11;2292:4;2284:5;2280:2;2276:14;2272:25;2266:32;2263:1;2255:44;2357:4;2349:5;2345:2;2341:14;2337:25;2331:32;2328:1;2320:44;2421:4;2413:5;2410:1;2406:13;2402:24;2396:31;2393:1;2385:43;2477:4;2470:5;2466:16;2460:23;2457:1;2449:35;;2523:4;2517:11;2512:3;2505:24;2567:1;2562:3;2558:11;2551:18;;2628:3;2623;2620:12;2038:623;2610:33;2700:4;2691:14;2685:4;2678:28;-1:-1:-1;;;2845:1:2;2829:18;;2826:1;2822:26;2956:11;;;2949:37;;;;3134:1;3075:17;;3068:25;3064:33;;;3121:11;;;;3114:22;3206:21;;3191:37;;980:2283;;722:2557;;;;;:::o;34618:2085:3:-;34728:22;34766:24;34793:29;34803:7;34812:9;34793;:29::i;:::-;34766:56;;34911:4;34907:9;34958:4;34949:7;34945:18;35035:1;35025:7;35019:14;35015:22;35012:1;35008:30;34998:8;34994:45;35085:7;35079:14;35075:1;35063:10;35059:18;35052:42;35143:1;35133:7;35127:14;35123:22;35114:7;35107:39;35176:1;35190:1311;35239:8;35233:15;35282:4;35272:8;35265:22;35324:9;35317:5;35314:20;35304:1015;;35379:4;35373:11;35437:9;35430:5;35426:21;35484:13;35475:7;35468:30;35637:1;35630:4;35615:13;35611:24;35607:32;35592:271;35707:23;;;35703:31;;35697:38;35680:15;;;35673:63;35766:9;;35819:22;35592:271;35819:22;-1:-1:-1;35989:1:3;35949:38;;;35966:4;35949:38;35942:49;36185:4;36166:24;36162:32;;36149:46;;36143:4;36136:60;36276:25;;35304:1015;36360:16;;36420:4;36406:19;;;;;36349:28;;-1:-1:-1;36452:24:3;;;35190:1311;36442:45;35194:2;;;;36524:7;36514:17;;36560:9;36554:16;36544:143;;36613:4;36604:7;36600:18;36590:28;;36670:1;36660:7;36654:14;36650:22;36642:6;36635:38;36544:143;34884:1813;34618:2085;;;;:::o;4131:227:5:-;4221:13;4253:98;4279:34;;;;;;;;;;;;;;-1:-1:-1;;;4279:34:5;;;4307:5;4279:13;:34::i;:::-;4320:29;;;;;;;;;;;;;;-1:-1:-1;;;4320:29:5;;;4343:5;4320:13;:29::i;1645:1641:3:-;1701:17;2146:4;2139;2133:11;2129:22;2122:29;;2245:4;2240:3;2236:14;2230:4;2223:28;2326:1;2321:3;2314:14;2427:3;2457:1;2453:6;2666:5;2648:402;2704:11;;;;2885:2;2899;2889:13;;2881:22;2704:11;2868:36;2991:2;2981:13;;3011:25;2648:402;3011:25;-1:-1:-1;;3078:13:3;;;-1:-1:-1;;3191:14:3;;;3251:19;;;3191:14;1645:1641;-1:-1:-1;1645:1641:3:o;2843:128:0:-;2907:13;2939:25;2945:18;2956:6;2945:10;:18::i;:::-;2939:5;:25::i;45660:128:3:-;45720:20;45761;45772:1;45775:5;45761:10;:20::i;31939:2575::-;32050:23;32182:7;32176:14;32229:6;32223:13;32277;32263:12;32260:31;32250:2248;;32335:4;32326:7;32322:18;32311:29;;32379:4;32371:6;32367:17;32357:27;;32428:4;32421;32415:11;32411:22;32401:32;;32471:7;32571:1;32556:12;32540:13;32531:7;32527:27;32523:46;32519:54;32599:1;32644:4;32630:12;32627:22;32617:74;;-1:-1:-1;32658:31:3;;;32617:74;32752:4;32738:12;32734:23;32728:4;32724:34;32721:1;32717:42;32791:6;32785:13;32815:1218;32864:7;32858:14;33042:1;33039;33035:9;33032:1;33028:17;33018:879;;33076:1;33073:326;;;33155:1;33140:12;33131:7;33121:32;33118:39;33108:265;;33217:1;33208:7;33204:15;33193:26;;33274:16;33265:7;33262:29;33252:50;;33295:5;;;33252:50;33335:8;32815:1218;;33108:265;33486:26;;;33471:42;;33665:26;;;;33560:4;33548:17;;;;33716:159;;;;33784:16;33775:7;33772:29;33762:50;;33805:5;;;33716:159;33018:879;33942:1;33933:7;33929:15;33918:26;;33987:16;33978:7;33975:29;32815:1218;33965:50;32815:1218;-1:-1:-1;;34169:4:3;34163:11;;-1:-1:-1;;34262:33:3;;;;34259:1;34255:41;34240:57;;34289:4;34463:20;;;34450:34;;-1:-1:-1;;;32250:2248:3;;;31939:2575;;;;:::o;4171:124:0:-;4238:13;4270:18;4276:6;4270:18;;;;;;;;;;;;;-1:-1:-1;;;4270:18:0;;;:5;:18::i;694:128::-;753:13;804:5;785:30;;;;;;;;:::i;43188:2391:3:-;43414:8;;43456:4;43450:11;43463:4;43446:22;;43407:16;;43481:111;;;;43534:2;43526:6;43518:19;43571:6;43568:1;43564:14;43554:24;;43481:111;43845:58;43839:4;43832:72;43978:30;44021:1143;44041:3;44038:1;44035:10;44021:1143;;44080:1;44077;44073:9;44068:14;;44122:4;44118:1;44112:8;44108:19;44160:4;44157:1;44154:11;44144:461;;44214:1;44210;44207;44203:9;44199:17;44189:226;;44309:1;44301:6;44293:18;44358:1;44350:6;44346:14;44336:24;;44385:8;44021:1143;;44189:226;44452:4;44444:6;44436:21;44511:1;44507;44499:6;44495:14;44487:26;44556:1;44548:6;44544:14;44534:24;;44579:8;44021:1143;;44144:461;44647:6;44643:1;44640;44636:9;44632:22;44622:382;;44765:1;44762;44758:9;44752:16;44746:4;44738:31;44831:2;44828:1;44824:10;44818:17;44812:4;44804:32;44892:4;44886:11;44878:6;44871:27;44955:1;44947:6;44943:14;44933:24;;44978:8;44021:1143;;44622:382;45037:4;45029:6;45021:21;45105:1;45102;45098:9;45092:16;45088:1;45080:6;45076:14;45068:41;;45148:1;45140:6;45136:14;45126:24;;44021:1143;;;44025:2;;45180:15;45177:111;;;45230:2;45222:6;45214:19;45264:1;45260:14;45177:111;45345:1;45332:15;;45414:4;45408:11;;-1:-1:-1;;45447:28:3;;;;45432:44;;45469:4;45523:15;;;45510:29;;45408:11;43188:2391;-1:-1:-1;;43188:2391:3:o;4873:371:0:-;4960:13;4989:6;:13;5006:1;4989:18;4985:58;;-1:-1:-1;5023:9:0;;;;;;;;;-1:-1:-1;5023:9:0;;;;4985:58;5052:20;5075:6;5082:1;5075:9;;;;;;;;:::i;:::-;;;;;;;5052:32;;5099:9;5111:1;5099:13;;5094:121;5118:6;:13;5114:1;:17;5094:121;;;5175:6;5183:9;5194:6;5201:1;5194:9;;;;;;;;:::i;:::-;;;;;;;5161:43;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;5161:43:0;;;;;;;;;;-1:-1:-1;5133:3:0;;5094:121;;14:286:13;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:13;;209:43;;199:71;;266:1;263;256:12;497:250;582:1;592:113;606:6;603:1;600:13;592:113;;;682:11;;;676:18;663:11;;;656:39;628:2;621:10;592:113;;;-1:-1:-1;;739:1:13;721:16;;714:27;497:250::o;752:396::-;901:2;890:9;883:21;864:4;933:6;927:13;976:6;971:2;960:9;956:18;949:34;992:79;1064:6;1059:2;1048:9;1044:18;1039:2;1031:6;1027:15;992:79;:::i;:::-;1132:2;1111:15;-1:-1:-1;;1107:29:13;1092:45;;;;1139:2;1088:54;;752:396;-1:-1:-1;;752:396:13:o;1153:131::-;-1:-1:-1;;;;;1228:31:13;;1218:42;;1208:70;;1274:1;1271;1264:12;1208:70;1153:131;:::o;1289:247::-;1348:6;1401:2;1389:9;1380:7;1376:23;1372:32;1369:52;;;1417:1;1414;1407:12;1369:52;1456:9;1443:23;1475:31;1500:5;1475:31;:::i;1749:180::-;1808:6;1861:2;1849:9;1840:7;1836:23;1832:32;1829:52;;;1877:1;1874;1867:12;1829:52;-1:-1:-1;1900:23:13;;1749:180;-1:-1:-1;1749:180:13:o;1934:315::-;2002:6;2010;2063:2;2051:9;2042:7;2038:23;2034:32;2031:52;;;2079:1;2076;2069:12;2031:52;2118:9;2105:23;2137:31;2162:5;2137:31;:::i;:::-;2187:5;2239:2;2224:18;;;;2211:32;;-1:-1:-1;;;1934:315:13:o;2436:456::-;2513:6;2521;2529;2582:2;2570:9;2561:7;2557:23;2553:32;2550:52;;;2598:1;2595;2588:12;2550:52;2637:9;2624:23;2656:31;2681:5;2656:31;:::i;:::-;2706:5;-1:-1:-1;2763:2:13;2748:18;;2735:32;2776:33;2735:32;2776:33;:::i;:::-;2436:456;;2828:7;;-1:-1:-1;;;2882:2:13;2867:18;;;;2854:32;;2436:456::o;3130:632::-;3301:2;3353:21;;;3423:13;;3326:18;;;3445:22;;;3272:4;;3301:2;3524:15;;;;3498:2;3483:18;;;3272:4;3567:169;3581:6;3578:1;3575:13;3567:169;;;3642:13;;3630:26;;3711:15;;;;3676:12;;;;3603:1;3596:9;3567:169;;;-1:-1:-1;3753:3:13;;3130:632;-1:-1:-1;;;;;;3130:632:13:o;3767:615::-;3853:6;3861;3914:2;3902:9;3893:7;3889:23;3885:32;3882:52;;;3930:1;3927;3920:12;3882:52;3970:9;3957:23;3999:18;4040:2;4032:6;4029:14;4026:34;;;4056:1;4053;4046:12;4026:34;4094:6;4083:9;4079:22;4069:32;;4139:7;4132:4;4128:2;4124:13;4120:27;4110:55;;4161:1;4158;4151:12;4110:55;4201:2;4188:16;4227:2;4219:6;4216:14;4213:34;;;4243:1;4240;4233:12;4213:34;4296:7;4291:2;4281:6;4278:1;4274:14;4270:2;4266:23;4262:32;4259:45;4256:65;;;4317:1;4314;4307:12;4256:65;4348:2;4340:11;;;;;4370:6;;-1:-1:-1;3767:615:13;;-1:-1:-1;;;;3767:615:13:o;4387:416::-;4452:6;4460;4513:2;4501:9;4492:7;4488:23;4484:32;4481:52;;;4529:1;4526;4519:12;4481:52;4568:9;4555:23;4587:31;4612:5;4587:31;:::i;:::-;4637:5;-1:-1:-1;4694:2:13;4679:18;;4666:32;4736:15;;4729:23;4717:36;;4707:64;;4767:1;4764;4757:12;4707:64;4790:7;4780:17;;;4387:416;;;;;:::o;4808:936::-;4905:6;4913;4921;4929;4937;4990:3;4978:9;4969:7;4965:23;4961:33;4958:53;;;5007:1;5004;4997:12;4958:53;5046:9;5033:23;5065:31;5090:5;5065:31;:::i;:::-;5115:5;-1:-1:-1;5172:2:13;5157:18;;5144:32;5185:33;5144:32;5185:33;:::i;:::-;5237:7;-1:-1:-1;5291:2:13;5276:18;;5263:32;;-1:-1:-1;5346:2:13;5331:18;;5318:32;5369:18;5399:14;;;5396:34;;;5426:1;5423;5416:12;5396:34;5464:6;5453:9;5449:22;5439:32;;5509:7;5502:4;5498:2;5494:13;5490:27;5480:55;;5531:1;5528;5521:12;5480:55;5571:2;5558:16;5597:2;5589:6;5586:14;5583:34;;;5613:1;5610;5603:12;5583:34;5658:7;5653:2;5644:6;5640:2;5636:15;5632:24;5629:37;5626:57;;;5679:1;5676;5669:12;5626:57;4808:936;;;;-1:-1:-1;4808:936:13;;-1:-1:-1;5710:2:13;5702:11;;5732:6;4808:936;-1:-1:-1;;;4808:936:13:o;5749:388::-;5817:6;5825;5878:2;5866:9;5857:7;5853:23;5849:32;5846:52;;;5894:1;5891;5884:12;5846:52;5933:9;5920:23;5952:31;5977:5;5952:31;:::i;:::-;6002:5;-1:-1:-1;6059:2:13;6044:18;;6031:32;6072:33;6031:32;6072:33;:::i;6142:251::-;6212:6;6265:2;6253:9;6244:7;6240:23;6236:32;6233:52;;;6281:1;6278;6271:12;6233:52;6313:9;6307:16;6332:31;6357:5;6332:31;:::i;6398:184::-;6468:6;6521:2;6509:9;6500:7;6496:23;6492:32;6489:52;;;6537:1;6534;6527:12;6489:52;-1:-1:-1;6560:16:13;;6398:184;-1:-1:-1;6398:184:13:o;6587:127::-;6648:10;6643:3;6639:20;6636:1;6629:31;6679:4;6676:1;6669:15;6703:4;6700:1;6693:15;6719:127;6780:10;6775:3;6771:20;6768:1;6761:31;6811:4;6808:1;6801:15;6835:4;6832:1;6825:15;7510:451;7762:31;7757:3;7750:44;7732:3;7823:6;7817:13;7839:75;7907:6;7902:2;7897:3;7893:12;7886:4;7878:6;7874:17;7839:75;:::i;:::-;7934:16;;;;7952:2;7930:25;;7510:451;-1:-1:-1;;7510:451:13:o;8159:897::-;8239:6;8292:2;8280:9;8271:7;8267:23;8263:32;8260:52;;;8308:1;8305;8298:12;8260:52;8341:9;8335:16;8370:18;8411:2;8403:6;8400:14;8397:34;;;8427:1;8424;8417:12;8397:34;8465:6;8454:9;8450:22;8440:32;;8510:7;8503:4;8499:2;8495:13;8491:27;8481:55;;8532:1;8529;8522:12;8481:55;8561:2;8555:9;8583:2;8579;8576:10;8573:36;;;8589:18;;:::i;:::-;8664:2;8658:9;8632:2;8718:13;;-1:-1:-1;;8714:22:13;;;8738:2;8710:31;8706:40;8694:53;;;8762:18;;;8782:22;;;8759:46;8756:72;;;8808:18;;:::i;:::-;8848:10;8844:2;8837:22;8883:2;8875:6;8868:18;8923:7;8918:2;8913;8909;8905:11;8901:20;8898:33;8895:53;;;8944:1;8941;8934:12;8895:53;8957:68;9022:2;9017;9009:6;9005:15;9000:2;8996;8992:11;8957:68;:::i;:::-;9044:6;8159:897;-1:-1:-1;;;;;;;8159:897:13:o;9061:448::-;9313:28;9308:3;9301:41;9283:3;9371:6;9365:13;9387:75;9455:6;9450:2;9445:3;9441:12;9434:4;9426:6;9422:17;9387:75;:::i;:::-;9482:16;;;;9500:2;9478:25;;9061:448;-1:-1:-1;;9061:448:13:o;9514:629::-;9783:3;9821:6;9815:13;9837:66;9896:6;9891:3;9884:4;9876:6;9872:17;9837:66;:::i;:::-;-1:-1:-1;;;9925:16:13;;;9950:18;;;9993:13;;10015:78;9993:13;10080:1;10069:13;;10062:4;10050:17;;10015:78;:::i;:::-;10113:20;10135:1;10109:28;;9514:629;-1:-1:-1;;;;9514:629:13:o;10148:127::-;10209:10;10204:3;10200:20;10197:1;10190:31;10240:4;10237:1;10230:15;10264:4;10261:1;10254:15;10280:125;10345:9;;;10366:10;;;10363:36;;;10379:18;;:::i;10410:128::-;10477:9;;;10498:11;;;10495:37;;;10512:18;;:::i;10543:934::-;10992:3;11029:2;11024:3;11020:12;11053:2;11048:3;11041:15;11085:6;11079:13;11101:74;11168:6;11164:1;11159:3;11155:11;11148:4;11140:6;11136:17;11101:74;:::i;:::-;-1:-1:-1;;;11234:1:13;11194:16;;;11226:10;;;11219:37;11281:13;;11303:75;11281:13;11365:1;11357:10;;11350:4;11338:17;;11303:75;:::i;:::-;11397:17;11438:1;11430:10;;11423:22;;;;11469:1;11461:10;;;-1:-1:-1;;;;10543:934:13:o;11482:768::-;-1:-1:-1;;;11859:25:13;;11907:13;;11841:3;;11929:74;11907:13;11992:1;11983:11;;11976:4;11964:17;;11929:74;:::i;:::-;-1:-1:-1;;;12062:1:13;12022:16;;;12054:10;;;12047:34;12106:13;;12128:75;12106:13;12190:1;12182:10;;12175:4;12163:17;;12128:75;:::i;:::-;12223:17;12242:1;12219:25;;11482:768;-1:-1:-1;;;;11482:768:13:o;12255:563::-;-1:-1:-1;;;12591:3:13;12584:16;12566:3;12629:6;12623:13;12645:74;12712:6;12708:1;12703:3;12699:11;12692:4;12684:6;12680:17;12645:74;:::i;:::-;-1:-1:-1;;;12778:1:13;12738:16;;;;12770:10;;;12763:23;-1:-1:-1;12810:1:13;12802:10;;12255:563;-1:-1:-1;12255:563:13:o;12823:::-;-1:-1:-1;;;13159:3:13;13152:16;13134:3;13197:6;13191:13;13213:74;13280:6;13276:1;13271:3;13267:11;13260:4;13252:6;13248:17;13213:74;:::i;:::-;-1:-1:-1;;;13346:1:13;13306:16;;;;13338:10;;;13331:23;-1:-1:-1;13378:1:13;13370:10;;12823:563;-1:-1:-1;12823:563:13:o;13391:703::-;13618:3;13656:6;13650:13;13672:66;13731:6;13726:3;13719:4;13711:6;13707:17;13672:66;:::i;:::-;13801:13;;13760:16;;;;13823:70;13801:13;13760:16;13870:4;13858:17;;13823:70;:::i;:::-;13960:13;;13915:20;;;13982:70;13960:13;13915:20;14029:4;14017:17;;13982:70;:::i;:::-;14068:20;;13391:703;-1:-1:-1;;;;;13391:703:13:o

Swarm Source

ipfs://ec69e097faa40b1dd7edff68a2f5c690527e70894098594d1c74088f56d40ba0
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.