ETH Price: $3,740.59 (+3.49%)
Gas: 0.11 GWei

Contract

0x848e44F469e491B49bb1ab9780fC4E20E1B4A142

Overview

ETH Balance

Scroll LogoScroll LogoScroll Logo8.6199381 ETH

ETH Value

$32,243.63 (@ $3,740.59/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x764d25532567c18ec86cfece12f3473de14ec1b0cfec606cb819adab336afac9 -(pending)2024-12-01 18:31:162 days ago1733077876IN
0x848e44F4...0E1B4A142
0.0049046771 ETH(Pending)(Pending)
Set Approval For...116329002024-12-04 7:37:403 hrs ago1733297860IN
0x848e44F4...0E1B4A142
0 ETH0.000010540.06366658
Roll116310962024-12-04 6:05:465 hrs ago1733292346IN
0x848e44F4...0E1B4A142
0.00004952 ETH0.000011690.08
Roll116304292024-12-04 5:30:376 hrs ago1733290237IN
0x848e44F4...0E1B4A142
0.00010462 ETH0.000022250.06
Set Approval For...116212912024-12-03 21:16:5014 hrs ago1733260610IN
0x848e44F4...0E1B4A142
0 ETH0.000016590.06552428
Set Approval For...116162112024-12-03 16:41:5818 hrs ago1733244118IN
0x848e44F4...0E1B4A142
0 ETH0.000019150.06174865
Roll116078062024-12-03 9:27:1826 hrs ago1733218038IN
0x848e44F4...0E1B4A142
0.00005908 ETH0.000013220.09
Roll116018432024-12-03 4:14:3031 hrs ago1733199270IN
0x848e44F4...0E1B4A142
0.00009385 ETH0.000021480.06
Roll115863642024-12-02 14:35:1044 hrs ago1733150110IN
0x848e44F4...0E1B4A142
0.00013135 ETH0.000021930.04307885
Roll115863642024-12-02 14:35:1044 hrs ago1733150110IN
0x848e44F4...0E1B4A142
0.00013672 ETH0.000023380.04928128
Purchase115863612024-12-02 14:35:0844 hrs ago1733150108IN
0x848e44F4...0E1B4A142
0.00473308 ETH0.000027580.04307885
Purchase115863602024-12-02 14:35:0844 hrs ago1733150108IN
0x848e44F4...0E1B4A142
0.00471393 ETH0.000027580.04307884
Purchase115863602024-12-02 14:35:0844 hrs ago1733150108IN
0x848e44F4...0E1B4A142
0.00470912 ETH0.000027630.04315954
Set Approval For...115863602024-12-02 14:35:0844 hrs ago1733150108IN
0x848e44F4...0E1B4A142
0 ETH0.000012920.04307884
Purchase115863602024-12-02 14:35:0844 hrs ago1733150108IN
0x848e44F4...0E1B4A142
0.00470901 ETH0.000027450.04307885
Set Approval For...115863602024-12-02 14:35:0844 hrs ago1733150108IN
0x848e44F4...0E1B4A142
0 ETH0.000012950.04681444
Purchase115863582024-12-02 14:35:0644 hrs ago1733150106IN
0x848e44F4...0E1B4A142
0.0047156 ETH0.000027580.04307884
Purchase115863552024-12-02 14:35:0344 hrs ago1733150103IN
0x848e44F4...0E1B4A142
0.00471493 ETH0.000027450.04307884
Purchase115863542024-12-02 14:35:0244 hrs ago1733150102IN
0x848e44F4...0E1B4A142
0.00470804 ETH0.00002760.04308372
Set Approval For...115863162024-12-02 14:33:0844 hrs ago1733149988IN
0x848e44F4...0E1B4A142
0 ETH0.000012550.04683991
Set Approval For...115863152024-12-02 14:33:0744 hrs ago1733149987IN
0x848e44F4...0E1B4A142
0 ETH0.000012430.04294112
Roll115863152024-12-02 14:33:0744 hrs ago1733149987IN
0x848e44F4...0E1B4A142
0.00008007 ETH0.000025180.05230165
Set Approval For...115863142024-12-02 14:33:0444 hrs ago1733149984IN
0x848e44F4...0E1B4A142
0 ETH0.00001280.05595042
Set Approval For...115862852024-12-02 14:31:4244 hrs ago1733149902IN
0x848e44F4...0E1B4A142
0 ETH0.000013640.04569123
Roll115859282024-12-02 14:14:2145 hrs ago1733148861IN
0x848e44F4...0E1B4A142
0.00011941 ETH0.000029010.08
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
116304292024-12-04 5:30:376 hrs ago1733290237
0x848e44F4...0E1B4A142
0.00006249 ETH
116304292024-12-04 5:30:376 hrs ago1733290237
0x848e44F4...0E1B4A142
0.00004212 ETH
116018432024-12-03 4:14:3031 hrs ago1733199270
0x848e44F4...0E1B4A142
0.00006164 ETH
116018432024-12-03 4:14:3031 hrs ago1733199270
0x848e44F4...0E1B4A142
0.0000322 ETH
115863642024-12-02 14:35:1044 hrs ago1733150110
0x848e44F4...0E1B4A142
0.00005434 ETH
115863642024-12-02 14:35:1044 hrs ago1733150110
0x848e44F4...0E1B4A142
0.00007701 ETH
115863642024-12-02 14:35:1044 hrs ago1733150110
0x848e44F4...0E1B4A142
0.00005946 ETH
115863642024-12-02 14:35:1044 hrs ago1733150110
0x848e44F4...0E1B4A142
0.00007725 ETH
115863612024-12-02 14:35:0844 hrs ago1733150108
0x848e44F4...0E1B4A142
0.0000608 ETH
115863612024-12-02 14:35:0844 hrs ago1733150108
0x848e44F4...0E1B4A142
0.00046538 ETH
115863602024-12-02 14:35:0844 hrs ago1733150108
0x848e44F4...0E1B4A142
0.0000608 ETH
115863602024-12-02 14:35:0844 hrs ago1733150108
0x848e44F4...0E1B4A142
0.00044622 ETH
115863602024-12-02 14:35:0844 hrs ago1733150108
0x848e44F4...0E1B4A142
0.00006088 ETH
115863602024-12-02 14:35:0844 hrs ago1733150108
0x848e44F4...0E1B4A142
0.00044134 ETH
115863602024-12-02 14:35:0844 hrs ago1733150108
0x848e44F4...0E1B4A142
0.0000608 ETH
115863602024-12-02 14:35:0844 hrs ago1733150108
0x848e44F4...0E1B4A142
0.00044131 ETH
115863582024-12-02 14:35:0644 hrs ago1733150106
0x848e44F4...0E1B4A142
0.0000608 ETH
115863582024-12-02 14:35:0644 hrs ago1733150106
0x848e44F4...0E1B4A142
0.0004479 ETH
115863552024-12-02 14:35:0344 hrs ago1733150103
0x848e44F4...0E1B4A142
0.0000608 ETH
115863552024-12-02 14:35:0344 hrs ago1733150103
0x848e44F4...0E1B4A142
0.00044722 ETH
115863542024-12-02 14:35:0244 hrs ago1733150102
0x848e44F4...0E1B4A142
0.00006081 ETH
115863542024-12-02 14:35:0244 hrs ago1733150102
0x848e44F4...0E1B4A142
0.00044032 ETH
115863152024-12-02 14:33:0744 hrs ago1733149987
0x848e44F4...0E1B4A142
0.00006507 ETH
115863152024-12-02 14:33:0744 hrs ago1733149987
0x848e44F4...0E1B4A142
0.00001499 ETH
115859282024-12-02 14:14:2145 hrs ago1733148861
0x848e44F4...0E1B4A142
0.00008317 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Dice

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 1000 runs

Other Settings:
paris EvmVersion
File 1 of 22 : Dice.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ERC721, ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pseudorandom} from "./lib/Pseudorandom.sol";
import {IDice} from "./interfaces/IDice.sol";
import {IAnyrand} from "./interfaces/IAnyrand.sol";
import {IRandomiserCallbackV3} from "./interfaces/IRandomiserCallbackV3.sol";
import {DiceMetadata} from "./DiceMetadata.sol";

/// @title Dice
/// @custom:version 1.0.0
/// @notice 1 token = 1 die
contract Dice is
    IDice,
    DiceMetadata,
    IRandomiserCallbackV3,
    ERC721Enumerable,
    Ownable
{
    using Strings for uint256;

    /// @notice Callback gas limit for a reveal call
    uint256 public constant CALLBACK_GAS_REVEAL_OVERHEAD = 300_000;
    /// @notice Callback gas limit per quantity of reveal
    uint256 public constant CALLBACK_GAS_PER_REVEAL = 150_000;
    /// @notice Callback gas limit for a roll call
    uint256 public constant CALLBACK_GAS_ROLL_OVERHEAD = 300_000;
    /// @notice Callback gas limit per quantity of roll
    uint256 public constant CALLBACK_GAS_PER_ROLL = 50_000;

    /// @notice Purchase price for a die
    uint256 public immutable price;
    /// @notice Token states
    mapping(uint256 tokenId => TokenState) public tokenStates;
    /// @notice Die rolls
    mapping(uint256 tokenId => uint256[]) public rolls;
    /// @notice Anyrand coordinator
    address internal immutable _randomiser;
    /// @notice Randomness request routing information
    mapping(uint256 requestId => RequestInfo) internal _requestInfos;
    /// @notice Timestamp of mint start
    uint256 public mintStartedAt;
    /// @notice Limited edition model rarity
    TokenRarity public immutable leModelRarity;
    /// @notice Limited edition model index
    uint256 public immutable leModelIdx;
    /// @notice How long the limited edition model is available for
    uint256 public immutable leModelPeriod;
    /// @notice Whether the limited edition model is still available to mint
    bool public isLimitedEditionModelAvailable;
    /// @notice Whether the contract is paused
    bool public isPaused;

    event MintStarted(uint256 timestamp);
    event TokenPurchased(
        uint256 indexed requestId,
        uint256 indexed tokenId,
        address indexed purchaser,
        uint256 price
    );
    event DieRollRequested(uint256 indexed tokenId, uint256 indexed requestId);
    event DieRolled(uint256 indexed tokenId, uint256 nthRoll, uint256 roll);
    event TokenRevealed(uint256 indexed tokenId, TokenMetadata metadata);
    event RandomnessIgnored(uint256 indexed requestId, uint256 randomness);
    event LimitedEditionModelRemoved(TokenRarity rarity, uint256 index);
    event PaymentExcessRefunded(address indexed to, uint256 amount);
    event ExternalURIUpdated(string externalURI);
    event WithdrawSucceeded(address indexed to, uint256 amount);
    event PauseToggled(bool indexed isPaused);

    constructor(
        uint256 price_,
        address randomiser_,
        string memory baseURI_,
        string[][] memory tokenModels_,
        TokenRarity leModelRarity_,
        uint256 leModelIdx_,
        uint256 leModelPeriod_
    )
        DiceMetadata(baseURI_, tokenModels_)
        ERC721("Dice", "DICE")
        Ownable(msg.sender)
    {
        price = price_;
        _randomiser = randomiser_;

        require(
            tokenModels_[uint256(leModelRarity_)].length > 1 &&
                leModelIdx_ < tokenModels_[uint256(leModelRarity_)].length,
            "Dice: min 2 models in same rarity as LE"
        );
        leModelRarity = leModelRarity_;
        leModelIdx = leModelIdx_;
        leModelPeriod = leModelPeriod_;
        isLimitedEditionModelAvailable = true;
    }

    /// @notice Only allow calls after mint has started
    modifier onlyAfterMintStarted() {
        require(mintStartedAt != 0, "Dice: mint not started");
        _;
    }

    /// @notice Only allow calls when the contract is not paused
    modifier whenNotPaused() {
        require(!isPaused, "Dice: contract is paused");
        _;
    }

    /// @notice Toggle contract pause
    /// @param isPaused_ Whether to pause the contract
    function pause(bool isPaused_) external onlyOwner {
        isPaused = isPaused_;
        emit PauseToggled(isPaused_);
    }

    /// @notice Enable minting
    function start() external onlyOwner {
        require(mintStartedAt == 0, "Dice: mint already started");
        mintStartedAt = block.timestamp;
        emit MintStarted(block.timestamp);
    }

    /// @notice Get the randomiser address
    function randomiser() public view virtual returns (address) {
        return _randomiser;
    }

    /// @notice Get the request info for a VRF request ID
    /// @param requestId VRF request ID
    function requestInfos(
        uint256 requestId
    ) external view returns (RequestInfo memory) {
        return _requestInfos[requestId];
    }

    /// @notice Helper function to get purchase price (NFT purchase price + VRF request price)
    /// @param quantity How many to purchase
    function getPurchasePrice(
        uint256 quantity
    ) external view returns (uint256) {
        (uint256 requestPrice, ) = IAnyrand(randomiser()).getRequestPrice(
            CALLBACK_GAS_REVEAL_OVERHEAD + CALLBACK_GAS_PER_REVEAL * quantity
        );
        return quantity * price + requestPrice;
    }

    /// @notice Remove the limited edition model after 48h
    function _removeLimitedEditionModel() internal {
        if (!isLimitedEditionModelAvailable) {
            // Already removed
            return;
        }

        // Not removed -> check if it needs to be removed
        if (block.timestamp < mintStartedAt + leModelPeriod) {
            // LE mint not yet over
            return;
        }

        // Remove the limited edition model
        TokenMetadata[] storage models = _tokenModels[leModelRarity];
        TokenMetadata memory lastModel = models[models.length - 1];
        // Fix (update) the last model's index -- rarity is the same
        lastModel.index = uint248(leModelIdx);
        // Swap LE model with (updated) last model
        models[leModelIdx] = lastModel;
        // Pop last model
        models.pop();
        // Disable this code from ever running again
        isLimitedEditionModelAvailable = false;
        emit LimitedEditionModelRemoved(leModelRarity, leModelIdx);
    }

    /// @notice Purchase di(c)e
    /// @param quantity How many to purchase
    function purchase(
        uint256 quantity
    ) external payable onlyAfterMintStarted whenNotPaused {
        _removeLimitedEditionModel();
        uint256 totalGasLimit = CALLBACK_GAS_REVEAL_OVERHEAD +
            CALLBACK_GAS_PER_REVEAL *
            quantity;
        (uint256 requestPrice, ) = IAnyrand(randomiser()).getRequestPrice(
            totalGasLimit
        );
        uint256 totalPrice = (quantity * price) + requestPrice;
        require(msg.value >= totalPrice, "Dice: insufficient payment");
        if (msg.value > totalPrice) {
            // refund excess
            (bool success, ) = payable(msg.sender).call{
                value: msg.value - totalPrice
            }("");
            require(success, "Dice: Refund failed");
            emit PaymentExcessRefunded(msg.sender, msg.value - totalPrice);
        }

        uint256 startingTokenId = totalSupply() + 1;
        uint256[] memory tokenIds = new uint256[](quantity);
        for (uint256 i = 0; i < quantity; ++i) {
            tokenIds[i] = startingTokenId + i;
            tokenStates[tokenIds[i]] = TokenState.Minted;
        }

        uint256 requestId = IAnyrand(randomiser()).requestRandomness{
            value: requestPrice
        }(block.timestamp + 30 seconds, totalGasLimit);
        _requestInfos[requestId] = RequestInfo({
            kind: RequestKind.Mint,
            tokenIds: tokenIds
        });

        for (uint256 i = 0; i < quantity; ++i) {
            _safeMint(msg.sender, tokenIds[i]);
            emit TokenPurchased(requestId, tokenIds[i], msg.sender, totalPrice);
        }
    }

    /// @notice Helper function to get roll price (VRF request price)
    /// @param quantity How many rolls
    function getRollPrice(uint256 quantity) external view returns (uint256) {
        (uint256 requestPrice, ) = IAnyrand(randomiser()).getRequestPrice(
            CALLBACK_GAS_ROLL_OVERHEAD + CALLBACK_GAS_PER_ROLL * quantity
        );
        return requestPrice;
    }

    /// @notice Roll a die
    /// @param tokenIds Token ids of dice
    function roll(uint256[] calldata tokenIds) external payable whenNotPaused {
        uint256 totalGasLimit = CALLBACK_GAS_ROLL_OVERHEAD +
            CALLBACK_GAS_PER_ROLL *
            tokenIds.length;
        (uint256 requestPrice, ) = IAnyrand(randomiser()).getRequestPrice(
            totalGasLimit
        );
        require(msg.value >= requestPrice, "Dice: insufficient payment");
        if (msg.value > requestPrice) {
            // refund excess
            (bool success, ) = payable(msg.sender).call{
                value: msg.value - requestPrice
            }("");
            require(success, "Dice: refund failed");
            emit PaymentExcessRefunded(msg.sender, msg.value - requestPrice);
        }

        for (uint256 i; i < tokenIds.length; ++i) {
            require(msg.sender == ownerOf(tokenIds[i]), "Dice: invalid sender");
            require(
                tokenStates[tokenIds[i]] == TokenState.Revealed,
                "Dice: token not revealed"
            );
            if (i == 0) continue;
            require(tokenIds[i] > tokenIds[i - 1], "Dice: unsorted tokenIds");
        }

        uint256 requestId = IAnyrand(randomiser()).requestRandomness{
            value: requestPrice
        }(block.timestamp + 30 seconds, totalGasLimit);
        _requestInfos[requestId] = RequestInfo({
            kind: RequestKind.Roll,
            tokenIds: tokenIds
        });

        for (uint256 i = 0; i < tokenIds.length; ++i)
            emit DieRollRequested(tokenIds[i], requestId);
    }

    /// @notice Anyrand callback
    function receiveRandomness(uint256 requestId, uint256 randomness) public {
        require(msg.sender == randomiser(), "Dice: invalid sender");
        RequestInfo storage requestInfo = _requestInfos[requestId];
        RequestKind requestKind = requestInfo.kind;
        requestInfo.kind = RequestKind.Nullified;
        if (requestKind == RequestKind.Mint) {
            // Reveal token
            _reveal(requestInfo.tokenIds, randomness);
            // Initial roll
            _roll(requestInfo.tokenIds, Pseudorandom.derive(randomness));
        } else if (requestKind == RequestKind.Roll) {
            // Roll die
            _roll(requestInfo.tokenIds, randomness);
        } else {
            // Dead request
            emit RandomnessIgnored(requestId, randomness);
        }
    }

    /// @notice Get total rolls for a die
    /// @param tokenId Token ID
    function getTotalRolls(uint256 tokenId) public view returns (uint256) {
        return rolls[tokenId].length;
    }

    /// @notice Roll dice
    /// @param tokenIds Token IDs
    /// @param randomness Seed
    function _roll(uint256[] memory tokenIds, uint256 randomness) internal {
        for (uint256 i; i < tokenIds.length; ++i) {
            uint256 tokenId = tokenIds[i];
            require(
                tokenStates[tokenId] == TokenState.Revealed,
                "Dice: invalid token state"
            );
            uint256 seed = Pseudorandom.derive(abi.encode(tokenId, randomness));
            uint256 y = Pseudorandom.pick(seed, 6);
            rolls[tokenId].push(y);
            uint256 totalRolls = getTotalRolls(tokenId);
            emit DieRolled(tokenId, totalRolls - 1, y);
        }
    }

    /// @notice Calc the rarity of a die from index out of 1_000_000
    /// @param y index
    function calcRarityFromIndex(uint256 y) public pure returns (TokenRarity) {
        assert(y < 1_000_000);
        TokenRarity rarity;
        if (y < 100) {
            // Legendary
            rarity = TokenRarity.Legendary;
        } else if (y < 100 + 5_000) {
            // Epic
            rarity = TokenRarity.Epic;
        } else if (y < 100 + 5_000 + 79_900) {
            // Rare
            rarity = TokenRarity.Rare;
        } else if (y < 100 + 5_000 + 79_900 + 335_000) {
            // Uncommon
            rarity = TokenRarity.Uncommon;
        } else {
            // Common
            rarity = TokenRarity.Common;
        }
        return rarity;
    }

    /// @notice Reveal the rarity of purchased dice
    /// @param tokenIds Token IDs
    /// @param randomness Seed
    function _reveal(uint256[] memory tokenIds, uint256 randomness) internal {
        for (uint256 i; i < tokenIds.length; ++i) {
            uint256 tokenId = tokenIds[i];
            require(
                tokenStates[tokenId] == TokenState.Minted,
                "Dice: invalid token state"
            );
            tokenStates[tokenId] = TokenState.Revealed;
            uint256 seed = Pseudorandom.derive(abi.encode(tokenId, randomness));
            // Derive rarity from seed
            uint256 r = Pseudorandom.pick(seed, 1_000_000);
            TokenRarity rarity = calcRarityFromIndex(r);
            // Derive token metadata from seed
            TokenMetadata[] storage models = _tokenModels[rarity];
            uint256 m = models.length == 1
                ? 0
                : Pseudorandom.pick(Pseudorandom.derive(seed), models.length);
            _assignTokenMetadata(tokenId, rarity, uint240(m));
            emit TokenRevealed(tokenId, models[m]);
        }
    }

    /// @notice Get the token URI for a die
    /// @param tokenId Token ID
    function tokenURI(
        uint256 tokenId
    ) public view virtual override returns (string memory) {
        _requireOwned(tokenId);
        require(
            tokenStates[tokenId] == TokenState.Revealed,
            "Dice: token not revealed"
        );
        return _tokenURI(tokenId);
    }

    /// @notice Get the token details for a die
    /// @param tokenId Token ID
    function getTokenDetails(
        uint256 tokenId
    ) external view returns (string memory uri, uint256 currentRoll) {
        uri = tokenURI(tokenId);
        uint256[] storage tokenRolls = rolls[tokenId];
        // tokenURI should revert unless revealed
        assert(tokenRolls.length > 0);
        return (uri, tokenRolls[tokenRolls.length - 1]);
    }

    /// @notice Set external URI
    /// @param externalURI New external URI
    function setExternalURI(string memory externalURI) external onlyOwner {
        __externalURI = externalURI;
        emit ExternalURIUpdated(externalURI);
    }

    /// @notice Withdraw proceeds
    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        (bool success, ) = msg.sender.call{value: balance}("");
        require(success, "Dice: withdraw failed");
        emit WithdrawSucceeded(msg.sender, balance);
    }
}

File 2 of 22 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

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

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

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

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

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

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

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

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

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

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

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

File 3 of 22 : draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

File 4 of 22 : ERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)

pragma solidity ^0.8.20;

import {IERC721} from "./IERC721.sol";
import {IERC721Receiver} from "./IERC721Receiver.sol";
import {IERC721Metadata} from "./extensions/IERC721Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {Strings} from "../../utils/Strings.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    mapping(uint256 tokenId => address) private _owners;

    mapping(address owner => uint256) private _balances;

    mapping(uint256 tokenId => address) private _tokenApprovals;

    mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;

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

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

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual returns (uint256) {
        if (owner == address(0)) {
            revert ERC721InvalidOwner(address(0));
        }
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual returns (address) {
        return _requireOwned(tokenId);
    }

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

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

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
        _requireOwned(tokenId);

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

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

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual {
        _approve(to, tokenId, _msgSender());
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual returns (address) {
        _requireOwned(tokenId);

        return _getApproved(tokenId);
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

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

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public virtual {
        if (to == address(0)) {
            revert ERC721InvalidReceiver(address(0));
        }
        // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
        // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
        address previousOwner = _update(to, tokenId, _msgSender());
        if (previousOwner != from) {
            revert ERC721IncorrectOwner(from, tokenId, previousOwner);
        }
    }

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

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
        transferFrom(from, to, tokenId);
        _checkOnERC721Received(from, to, tokenId, data);
    }

    /**
     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
     *
     * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
     * core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances
     * consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
     * `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
     */
    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
        return _owners[tokenId];
    }

    /**
     * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
     */
    function _getApproved(uint256 tokenId) internal view virtual returns (address) {
        return _tokenApprovals[tokenId];
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
     * particular (ignoring whether it is owned by `owner`).
     *
     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
     * assumption.
     */
    function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
        return
            spender != address(0) &&
            (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
    }

    /**
     * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
     * Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
     * the `spender` for the specific `tokenId`.
     *
     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
     * assumption.
     */
    function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
        if (!_isAuthorized(owner, spender, tokenId)) {
            if (owner == address(0)) {
                revert ERC721NonexistentToken(tokenId);
            } else {
                revert ERC721InsufficientApproval(spender, tokenId);
            }
        }
    }

    /**
     * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
     *
     * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
     * a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
     *
     * WARNING: Increasing an account's balance using this function tends to be paired with an override of the
     * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
     * remain consistent with one another.
     */
    function _increaseBalance(address account, uint128 value) internal virtual {
        unchecked {
            _balances[account] += value;
        }
    }

    /**
     * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
     * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
     *
     * The `auth` argument is optional. If the value passed is non 0, then this function will check that
     * `auth` is either the owner of the token, or approved to operate on the token (by the owner).
     *
     * Emits a {Transfer} event.
     *
     * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
     */
    function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
        address from = _ownerOf(tokenId);

        // Perform (optional) operator check
        if (auth != address(0)) {
            _checkAuthorized(from, auth, tokenId);
        }

        // Execute the update
        if (from != address(0)) {
            // Clear approval. No need to re-authorize or emit the Approval event
            _approve(address(0), tokenId, address(0), false);

            unchecked {
                _balances[from] -= 1;
            }
        }

        if (to != address(0)) {
            unchecked {
                _balances[to] += 1;
            }
        }

        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        return from;
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal {
        if (to == address(0)) {
            revert ERC721InvalidReceiver(address(0));
        }
        address previousOwner = _update(to, tokenId, address(0));
        if (previousOwner != address(0)) {
            revert ERC721InvalidSender(address(0));
        }
    }

    /**
     * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - 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 tokenId) internal {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
        _mint(to, tokenId);
        _checkOnERC721Received(address(0), to, tokenId, data);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     * This is an internal function that does not check if the sender is authorized to operate on the token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal {
        address previousOwner = _update(address(0), tokenId, address(0));
        if (previousOwner == address(0)) {
            revert ERC721NonexistentToken(tokenId);
        }
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal {
        if (to == address(0)) {
            revert ERC721InvalidReceiver(address(0));
        }
        address previousOwner = _update(to, tokenId, address(0));
        if (previousOwner == address(0)) {
            revert ERC721NonexistentToken(tokenId);
        } else if (previousOwner != from) {
            revert ERC721IncorrectOwner(from, tokenId, previousOwner);
        }
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
     * are aware of the ERC721 standard to prevent tokens from being forever locked.
     *
     * `data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is like {safeTransferFrom} in the sense that it invokes
     * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `tokenId` token must exist and be owned by `from`.
     * - `to` cannot be the zero address.
     * - `from` 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 _safeTransfer(address from, address to, uint256 tokenId) internal {
        _safeTransfer(from, to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
        _transfer(from, to, tokenId);
        _checkOnERC721Received(from, to, tokenId, data);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
     * either the owner of the token, or approved to operate on all tokens held by this owner.
     *
     * Emits an {Approval} event.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address to, uint256 tokenId, address auth) internal {
        _approve(to, tokenId, auth, true);
    }

    /**
     * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
     * emitted in the context of transfers.
     */
    function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
        // Avoid reading the owner unless necessary
        if (emitEvent || auth != address(0)) {
            address owner = _requireOwned(tokenId);

            // We do not use _isAuthorized because single-token approvals should not be able to call approve
            if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
                revert ERC721InvalidApprover(auth);
            }

            if (emitEvent) {
                emit Approval(owner, to, tokenId);
            }
        }

        _tokenApprovals[tokenId] = to;
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Requirements:
     * - operator can't be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        if (operator == address(0)) {
            revert ERC721InvalidOperator(operator);
        }
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
     * Returns the owner.
     *
     * Overrides to ownership logic should be done to {_ownerOf}.
     */
    function _requireOwned(uint256 tokenId) internal view returns (address) {
        address owner = _ownerOf(tokenId);
        if (owner == address(0)) {
            revert ERC721NonexistentToken(tokenId);
        }
        return owner;
    }

    /**
     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
     * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param data bytes optional data to send along with the call
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
        if (to.code.length > 0) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
                if (retval != IERC721Receiver.onERC721Received.selector) {
                    revert ERC721InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert ERC721InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }
}

File 5 of 22 : ERC721Enumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol)

pragma solidity ^0.8.20;

import {ERC721} from "../ERC721.sol";
import {IERC721Enumerable} from "./IERC721Enumerable.sol";
import {IERC165} from "../../../utils/introspection/ERC165.sol";

/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability
 * of all the token ids in the contract as well as all token ids owned by each account.
 *
 * CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`,
 * interfere with enumerability and should not be used together with `ERC721Enumerable`.
 */
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    mapping(address owner => mapping(uint256 index => uint256)) private _ownedTokens;
    mapping(uint256 tokenId => uint256) private _ownedTokensIndex;

    uint256[] private _allTokens;
    mapping(uint256 tokenId => uint256) private _allTokensIndex;

    /**
     * @dev An `owner`'s token query was out of bounds for `index`.
     *
     * NOTE: The owner being `address(0)` indicates a global out of bounds index.
     */
    error ERC721OutOfBoundsIndex(address owner, uint256 index);

    /**
     * @dev Batch mint is not allowed.
     */
    error ERC721EnumerableForbiddenBatchMint();

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

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
        if (index >= balanceOf(owner)) {
            revert ERC721OutOfBoundsIndex(owner, index);
        }
        return _ownedTokens[owner][index];
    }

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

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual returns (uint256) {
        if (index >= totalSupply()) {
            revert ERC721OutOfBoundsIndex(address(0), index);
        }
        return _allTokens[index];
    }

    /**
     * @dev See {ERC721-_update}.
     */
    function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
        address previousOwner = super._update(to, tokenId, auth);

        if (previousOwner == address(0)) {
            _addTokenToAllTokensEnumeration(tokenId);
        } else if (previousOwner != to) {
            _removeTokenFromOwnerEnumeration(previousOwner, tokenId);
        }
        if (to == address(0)) {
            _removeTokenFromAllTokensEnumeration(tokenId);
        } else if (previousOwner != to) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }

        return previousOwner;
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        uint256 length = balanceOf(to) - 1;
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = balanceOf(from);
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }

    /**
     * See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch
     */
    function _increaseBalance(address account, uint128 amount) internal virtual override {
        if (amount > 0) {
            revert ERC721EnumerableForbiddenBatchMint();
        }
        super._increaseBalance(account, amount);
    }
}

File 6 of 22 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.20;

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

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

File 7 of 22 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.20;

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

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

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

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

File 8 of 22 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

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

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

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

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

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

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

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

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

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

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

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

File 9 of 22 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

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

File 10 of 22 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

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

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

File 11 of 22 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

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

File 12 of 22 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

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

File 13 of 22 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 14 of 22 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

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

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

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

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

File 15 of 22 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

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

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

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

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

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

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

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

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

File 16 of 22 : DiceMetadata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

import {Base64} from "solady/src/utils/Base64.sol";
import {LibString} from "solady/src/utils/LibString.sol";
import {IDice} from "./interfaces/IDice.sol";

/// @title DiceMetadata
/// @author Kevin Charm <[email protected]>
/// @notice Generates JSON metadata onchain
abstract contract DiceMetadata is IDice {
    using LibString for uint256;

    struct TokenMetadataPointer {
        bool isAssigned;
        TokenRarity rarity;
        uint240 index;
    }

    /// @notice External URI base for external_url
    string public __externalURI = "https://dice.anyrand.com/dice/?id=";
    /// @notice Base URI for token metadata
    string public __baseURI;
    /// @notice Mapping of rarities to indices of tokenModelIds
    mapping(TokenRarity rarity => TokenMetadata[] models) internal _tokenModels;
    /// @notice Mapping of minted token IDs to models
    mapping(uint256 tokenId => TokenMetadataPointer) internal _tokenMetadatas;

    constructor(string memory baseURI_, string[][] memory tokenModels_) {
        __baseURI = baseURI_;

        require(
            tokenModels_.length == (uint256(type(TokenRarity).max) + 1),
            "Dice: Incomplete rarity set"
        );
        for (uint256 r; r < tokenModels_.length; ++r) {
            TokenRarity rarity = TokenRarity(r);
            string[] memory models = tokenModels_[r];
            require(
                models.length > 0,
                "Dice: Rarity must have at least one model"
            );
            for (uint240 i; i < models.length; ++i) {
                _tokenModels[rarity].push(
                    TokenMetadata({rarity: rarity, index: i, name: models[i]})
                );
            }
        }
    }

    function _assignTokenMetadata(
        uint256 tokenId,
        TokenRarity rarity,
        uint240 index
    ) internal {
        require(
            !_tokenMetadatas[tokenId].isAssigned,
            "Dice: Token metadata already assigned"
        );
        _tokenMetadatas[tokenId] = TokenMetadataPointer({
            isAssigned: true,
            rarity: rarity,
            index: index
        });
    }

    function getTokenModelsByRarity(
        TokenRarity rarity
    ) public view returns (TokenMetadata[] memory) {
        return _tokenModels[rarity];
    }

    function getTokenModel(
        TokenRarity rarity,
        uint240 index
    ) public view returns (TokenMetadata memory) {
        return _tokenModels[rarity][index];
    }

    function getTokenMetadata(
        uint256 tokenId
    ) public view returns (TokenMetadata memory) {
        TokenMetadataPointer memory ptr = _tokenMetadatas[tokenId];
        require(ptr.isAssigned, "Dice: Token metadata not assigned");
        return _tokenModels[ptr.rarity][ptr.index];
    }

    function getRarityName(
        TokenRarity rarity
    ) public pure returns (string memory) {
        if (rarity == TokenRarity.Common) {
            return "Common";
        } else if (rarity == TokenRarity.Uncommon) {
            return "Uncommon";
        } else if (rarity == TokenRarity.Rare) {
            return "Rare";
        } else if (rarity == TokenRarity.Epic) {
            return "Epic";
        } else {
            // if (rarity == TokenRarity.Legendary)
            return "Legendary";
        }
    }

    function _tokenURI(uint256 tokenId) internal view returns (string memory) {
        TokenMetadata memory metadata = getTokenMetadata(tokenId);
        string memory externalURL = string.concat(
            __externalURI,
            tokenId.toString()
        );
        string memory r = uint256(metadata.rarity).toString();
        string memory i = uint256(metadata.index).toString();
        string memory image = string.concat(
            __baseURI,
            "img/",
            r,
            "/",
            i,
            ".png"
        );
        string memory gltf = string.concat(
            __baseURI,
            "gltf/",
            r,
            "/",
            i,
            ".glb"
        );
        string memory tokenIdStr = tokenId.toString();
        return
            string.concat(
                "data:application/json;base64,",
                Base64.encode(
                    abi.encodePacked(
                        '{"name":"Onchain Die #',
                        tokenIdStr,
                        '","description":"Reroll your dice using verifiable randomness on dice.anyrand.com","external_url":"',
                        externalURL,
                        '","image":"',
                        image,
                        '","animation_url":"',
                        gltf,
                        '","attributes": [{"trait_type":"Rarity","value":"',
                        getRarityName(metadata.rarity),
                        '"}, {"trait_type":"Model","value":"',
                        metadata.name,
                        '"}]}'
                    )
                )
            );
    }
}

File 17 of 22 : IAnyrand.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8;

interface IAnyrand {
    event RandomnessRequested(
        uint256 indexed requestId,
        address indexed requester,
        bytes32 indexed pubKeyHash,
        uint256 round,
        uint256 callbackGasLimit,
        uint256 feePaid,
        uint256 effectiveFeePerGas
    );
    event RandomnessFulfilled(
        uint256 indexed requestId,
        uint256[] randomWords,
        bool callbackSuccess,
        uint256 actualGasUsed
    );
    event RandomnessCallbackFailed(
        uint256 indexed requestId,
        bytes32 retdata,
        uint256 gasLimit,
        uint256 actualGasUsed
    );
    event RequestPremiumMultiplierUpdated(uint256 newPrice);
    event ETHWithdrawn(uint256 amount);
    event BeaconUpdated(address indexed newBeacon);
    event MaxCallbackGasLimitUpdated(uint256 newMaxCallbackGasLimit);
    event MaxDeadlineDeltaUpdated(uint256 maxDeadlineDelta);
    event GasStationUpdated(address indexed newGasStation);
    event MaxFeePerGasUpdated(uint256 maxFeePerGas);

    error TransferFailed(address to, uint256 value);
    error IncorrectPayment(uint256 got, uint256 want);
    error OverGasLimit(uint256 callbackGasLimit);
    error InvalidRequestHash(bytes32 requestHash);
    error InvalidDeadline(uint256 deadline);
    error InsufficientGas();
    error InvalidBeacon(address beacon);

    /// @notice Compute the total request price
    /// @param callbackGasLimit The callback gas limit that will be used for
    ///     the randomness request
    function getRequestPrice(
        uint256 callbackGasLimit
    ) external view returns (uint256 totalPrice, uint256 effectiveFeePerGas);

    /// @notice Request randomness
    /// @param deadline Timestamp of when the randomness should be fulfilled. A
    ///     beacon round closest to this timestamp (rounding up to the nearest
    ///     future round) will be used as the round from which to derive
    ///     randomness.
    /// @param callbackGasLimit Gas limit for callback
    function requestRandomness(
        uint256 deadline,
        uint256 callbackGasLimit
    ) external payable returns (uint256);
}

File 18 of 22 : IDice.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

interface IDice {
    enum TokenState {
        Unminted,
        Minted,
        Revealed
    }

    enum TokenRarity {
        Common,
        Uncommon,
        Rare,
        Epic,
        Legendary
    }

    /// @notice Represents metadata for a type of die
    struct TokenMetadata {
        /// @notice Rarity of the die
        TokenRarity rarity;
        /// @notice Index of the die in the rarity set
        uint248 index;
        /// @notice Name/value of the trait
        string name;
    }

    enum RequestKind {
        Nullified,
        Mint,
        Roll
    }

    struct RequestInfo {
        RequestKind kind;
        uint256[] tokenIds;
    }
}

File 19 of 22 : IRandomiserCallbackV3.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8;

interface IRandomiserCallbackV3 {
    /// @notice Receive random words from a randomiser.
    /// @dev Ensure that proper access control is enforced on this function;
    ///     only the designated randomiser may call this function and the
    ///     requestId should be as expected from the randomness request.
    /// @param requestId The identifier for the original randomness request
    /// @param randomWord Uniform random number in the range [0, 2**256)
    function receiveRandomness(uint256 requestId, uint256 randomWord) external;
}

File 20 of 22 : Pseudorandom.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

/// @title Pseudorandom
/// @author Kevin Charm <[email protected]>
/// @notice Pseudorandom. Not to be confused with the cat known as pseudotheos.
library Pseudorandom {
    uint256 private constant _UINT256_MAX = type(uint256).max;

    /// @notice Derive a pseudorandom number from a seed using bytes
    /// @param seed The input to derive from
    /// @return output keccak256(seed)
    function derive(bytes memory seed) internal pure returns (uint256 output) {
        assembly {
            let len := mload(seed)
            output := keccak256(add(seed, 0x20), len)
        }
    }

    /// @notice Derive a pseudorandom number from a seed using u256
    /// @param seed The input to derive from
    /// @return output keccak256(seed)
    function derive(uint256 seed) internal pure returns (uint256 output) {
        assembly {
            mstore(0x00, seed)
            output := keccak256(0x00, 0x20)
        }
    }

    /// @notice Derive a uniform random number in the range [0, max) from seed
    ///     without modulo bias.
    /// @param seed The input to derive from
    /// @param max The upper bound of the range
    /// @return A pseudorandom number in the range [0, max)
    function pick(uint256 seed, uint256 max) internal pure returns (uint256) {
        // modulo reduction of _UINT256_MAX by max
        uint256 ceiling = _UINT256_MAX - (_UINT256_MAX % max);
        uint256 candidate;
        do {
            candidate = derive(seed);
        } while (candidate >= ceiling);
        return candidate % max;
    }
}

File 21 of 22 : 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)

                let dataEnd := add(add(0x20, data), dataLength)
                let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot.
                mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits.

                // 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(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`.
                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 22 of 22 : 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)
///
/// @dev Note:
/// For performance and bytecode compactness, most of the string operations are restricted to
/// byte strings (7-bit ASCII), except where otherwise specified.
/// Usage of byte string operations on charsets with runes spanning two or more bytes
/// can lead to undefined behavior.
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();

    /// @dev The input string must be a 7-bit ASCII.
    error StringNot7BitASCII();

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

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

    /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
    uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;

    /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
    uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;

    /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'.
    uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;

    /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
    uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;

    /// @dev Lookup for '0123456789'.
    uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;

    /// @dev Lookup for '0123456789abcdefABCDEF'.
    uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;

    /// @dev Lookup for '01234567'.
    uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;

    /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'.
    uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;

    /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'.
    uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;

    /// @dev Lookup for ' \t\n\r\x0b\x0c'.
    uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;

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

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(uint256 value) internal pure returns (string memory result) {
        /// @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.
            result := add(mload(0x40), 0x80)
            mstore(0x40, add(result, 0x20)) // Allocate memory.
            mstore(result, 0) // Zeroize the slot after the string.

            let end := result // Cache the end of the memory to calculate the length later.
            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 {} {
                result := add(result, w) // `sub(result, 1)`.
                // Store the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(result, add(48, mod(temp, 10)))
                temp := div(temp, 10) // Keep dividing `temp` until zero.
                if iszero(temp) { break }
            }
            let n := sub(end, result)
            result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(int256 value) internal pure returns (string memory result) {
        if (value >= 0) return toString(uint256(value));
        unchecked {
            result = toString(~uint256(value) + 1);
        }
        /// @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 n := mload(result) // Load the string length.
            mstore(result, 0x2d) // Store the '-' character.
            result := sub(result, 1) // Move back the string pointer by a byte.
            mstore(result, add(n, 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 result)
    {
        result = toHexStringNoPrefix(value, length);
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(mload(result), 2) // Compute the length.
            mstore(result, 0x3078) // Store the "0x" prefix.
            result := sub(result, 2) // Move the pointer.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is not prefixed with "0x" and is 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 result)
    {
        /// @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.
            result := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
            mstore(0x40, add(result, 0x20)) // Allocate memory.
            mstore(result, 0) // Zeroize the slot after the string.

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

            let start := sub(result, 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 {} {
                result := add(result, w) // `sub(result, 2)`.
                mstore8(add(result, 1), mload(and(temp, 15)))
                mstore8(result, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(xor(result, start)) { break }
            }
            if temp {
                mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
                revert(0x1c, 0x04)
            }
            let n := sub(end, result)
            result := sub(result, 0x20)
            mstore(result, n) // Store the length.
        }
    }

    /// @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 result) {
        result = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(mload(result), 2) // Compute the length.
            mstore(result, 0x3078) // Store the "0x" prefix.
            result := sub(result, 2) // Move the pointer.
            mstore(result, n) // Store 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 result) {
        result = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
            let n := add(mload(result), 2) // Compute the length.
            mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero.
            result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero.
            mstore(result, sub(n, o)) // Store 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 result)
    {
        result = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
            let n := mload(result) // Get the length.
            result := add(result, o) // Move the pointer, accounting for leading zero.
            mstore(result, sub(n, o)) // Store 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 result) {
        /// @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.
            result := add(mload(0x40), 0x80)
            mstore(0x40, add(result, 0x20)) // Allocate memory.
            mstore(result, 0) // Zeroize the slot after the string.

            let end := result // Cache the end to calculate the length later.
            mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.

            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 {} {
                result := add(result, w) // `sub(result, 2)`.
                mstore8(add(result, 1), mload(and(temp, 15)))
                mstore8(result, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(temp) { break }
            }
            let n := sub(end, result)
            result := sub(result, 0x20)
            mstore(result, n) // Store the length.
        }
    }

    /// @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 result) {
        result = toHexString(value);
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
            let o := add(result, 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 result) {
        result = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(mload(result), 2) // Compute the length.
            mstore(result, 0x3078) // Store the "0x" prefix.
            result := sub(result, 2) // Move the pointer.
            mstore(result, n) // Store 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 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            // Allocate 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(result, 0x80))
            mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.

            result := add(result, 2)
            mstore(result, 40) // Store the length.
            let o := add(result, 0x20)
            mstore(add(o, 40), 0) // Zeroize the slot after the string.
            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 result) {
        result = toHexStringNoPrefix(raw);
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(mload(result), 2) // Compute the length.
            mstore(result, 0x3078) // Store the "0x" prefix.
            result := sub(result, 2) // Move the pointer.
            mstore(result, n) // Store 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 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(raw)
            result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
            mstore(result, add(n, n)) // Store the length of the output.

            mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
            let o := add(result, 0x20)
            let end := add(raw, n)
            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 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 {
            result := 1
            let mask := shl(7, div(not(0), 255))
            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)
            }
        }
    }

    /// @dev Returns if this string is a 7-bit ASCII string,
    /// AND all characters are in the `allowed` lookup.
    /// Note: If `s` is empty, returns true regardless of `allowed`.
    function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if mload(s) {
                let allowed_ := shr(128, shl(128, allowed))
                let o := add(s, 0x20)
                for { let end := add(o, mload(s)) } 1 {} {
                    result := and(result, shr(byte(0, mload(o)), allowed_))
                    o := add(o, 1)
                    if iszero(and(result, lt(o, end))) { break }
                }
            }
        }
    }

    /// @dev Converts the bytes in the 7-bit ASCII string `s` to
    /// an allowed lookup for use in `is7BitASCII(s, allowed)`.
    /// To save runtime gas, you can cache the result in an immutable variable.
    function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(s) {
                let o := add(s, 0x20)
                for { let end := add(o, mload(s)) } 1 {} {
                    result := or(result, shl(byte(0, mload(o)), 1))
                    o := add(o, 1)
                    if iszero(lt(o, end)) { break }
                }
                if shr(128, result) {
                    mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

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

    // For performance and bytecode compactness, byte string operations are restricted
    // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
    // Usage of byte string operations on charsets with runes spanning two or more bytes
    // can lead to undefined behavior.

    /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
    function replace(string memory subject, string memory needle, string memory replacement)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let needleLen := mload(needle)
            let replacementLen := mload(replacement)
            let d := sub(result, subject) // Memory difference.
            let i := add(subject, 0x20) // Subject bytes pointer.
            let end := add(i, mload(subject))
            if iszero(gt(needleLen, mload(subject))) {
                let subjectSearchEnd := add(sub(end, needleLen), 1)
                let h := 0 // The hash of `needle`.
                if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
                let s := mload(add(needle, 0x20))
                for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
                    let t := mload(i)
                    // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(i, needleLen), h)) {
                                mstore(add(i, d), t)
                                i := add(i, 1)
                                if iszero(lt(i, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        for { let j := 0 } 1 {} {
                            mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
                            j := add(j, 0x20)
                            if iszero(lt(j, replacementLen)) { break }
                        }
                        d := sub(add(d, replacementLen), needleLen)
                        if needleLen {
                            i := add(i, needleLen)
                            if iszero(lt(i, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(add(i, d), t)
                    i := add(i, 1)
                    if iszero(lt(i, subjectSearchEnd)) { break }
                }
            }
            let n := add(sub(d, add(result, 0x20)), end)
            // Copy the rest of the string one word at a time.
            for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
            let o := add(i, d)
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(0x40, add(o, 0x20)) // Allocate memory.
            mstore(result, n) // Store the length.
        }
    }

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

                subject := add(subjectStart, from)
                let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
                let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
                let s := mload(add(needle, 0x20))

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

                if iszero(lt(needleLen, 0x20)) {
                    for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, needleLen), 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 `needle` in `subject`,
    /// needleing from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOf(string memory subject, string memory needle)
        internal
        pure
        returns (uint256 result)
    {
        result = indexOf(subject, needle, 0);
    }

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

                let fromMax := sub(mload(subject), needleLen)
                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(needle, 0x20), needleLen) } 1 {} {
                    if eq(keccak256(subject, needleLen), 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 `needle` in `subject`,
    /// needleing from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function lastIndexOf(string memory subject, string memory needle)
        internal
        pure
        returns (uint256 result)
    {
        result = lastIndexOf(subject, needle, type(uint256).max);
    }

    /// @dev Returns true if `needle` is found in `subject`, false otherwise.
    function contains(string memory subject, string memory needle) internal pure returns (bool) {
        return indexOf(subject, needle) != NOT_FOUND;
    }

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

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

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

    /// @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 subjectLen := mload(subject)
            if iszero(gt(subjectLen, end)) { end := subjectLen }
            if iszero(gt(subjectLen, start)) { start := subjectLen }
            if lt(start, end) {
                result := mload(0x40)
                let n := sub(end, start)
                let i := add(subject, start)
                let w := not(0x1f)
                // Copy the `subject` one word at a time, backwards.
                for { let j := and(add(n, 0x1f), w) } 1 {} {
                    mstore(add(result, j), mload(add(i, j)))
                    j := add(j, w) // `sub(j, 0x20)`.
                    if iszero(j) { break }
                }
                let o := add(add(result, 0x20), n)
                mstore(o, 0) // Zeroize the slot after the string.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
                mstore(result, n) // Store the length.
            }
        }
    }

    /// @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, type(uint256).max);
    }

    /// @dev Returns all the indices of `needle` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(string memory subject, string memory needle)
        internal
        pure
        returns (uint256[] memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLen := mload(needle)
            if iszero(gt(searchLen, mload(subject))) {
                result := mload(0x40)
                let i := add(subject, 0x20)
                let o := add(result, 0x20)
                let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
                let h := 0 // The hash of `needle`.
                if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
                let s := mload(add(needle, 0x20))
                for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
                    let t := mload(i)
                    // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(i, searchLen), h)) {
                                i := add(i, 1)
                                if iszero(lt(i, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
                        o := add(o, 0x20)
                        i := add(i, searchLen) // Advance `i` by `searchLen`.
                        if searchLen {
                            if iszero(lt(i, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    i := add(i, 1)
                    if iszero(lt(i, subjectSearchEnd)) { break }
                }
                mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(o, 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))
            for { let prevIndex := 0 } 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let l := sub(index, prevIndex)
                    mstore(element, l) // Store the length of the element.
                    // Copy the `subject` one word at a time, backwards.
                    for { let o := and(add(l, 0x1f), w) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := add(o, w) // `sub(o, 0x20)`.
                        if iszero(o) { break }
                    }
                    mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the string.
                    // Allocate memory for the length and the bytes, rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(l, 0x3f), w)))
                    mstore(indexPtr, element) // Store the `element` into the array.
                }
                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 {
            result := mload(0x40)
            let w := not(0x1f)
            let aLen := mload(a)
            // Copy `a` one word at a time, backwards.
            for { let o := and(add(aLen, 0x20), w) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let bLen := mload(b)
            let output := add(result, aLen)
            // Copy `b` one word at a time, backwards.
            for { let o := and(add(bLen, 0x20), w) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let totalLen := add(aLen, bLen)
            let last := add(add(result, 0x20), totalLen)
            mstore(last, 0) // Zeroize the slot after the string.
            mstore(result, totalLen) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate memory.
        }
    }

    /// @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 n := mload(subject)
            if n {
                result := mload(0x40)
                let o := add(result, 0x20)
                let d := sub(subject, result)
                let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
                for { let end := add(o, n) } 1 {} {
                    let b := byte(0, mload(add(d, o)))
                    mstore8(o, xor(and(shr(b, flags), 0x20), b))
                    o := add(o, 1)
                    if eq(o, end) { break }
                }
                mstore(result, n) // Store the length.
                mstore(o, 0) // Zeroize the slot after the string.
                mstore(0x40, add(o, 0x20)) // Allocate 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) // Store the length.
            let o := add(result, 0x20)
            mstore(o, s) // Store the bytes of the string.
            mstore(add(o, n), 0) // Zeroize the slot after the string.
            mstore(0x40, add(result, 0x40)) // Allocate memory.
        }
    }

    /// @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 {
            result := mload(0x40)
            let end := add(s, mload(s))
            let o := add(result, 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(o, c)
                    o := add(o, 1)
                    continue
                }
                let t := shr(248, mload(c))
                mstore(o, mload(and(t, 0x1f)))
                o := add(o, shr(5, t))
            }
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(result, sub(o, add(result, 0x20))) // Store the length.
            mstore(0x40, add(o, 0x20)) // Allocate 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 {
            result := mload(0x40)
            let o := add(result, 0x20)
            if addDoubleQuotes {
                mstore8(o, 34)
                o := add(1, o)
            }
            // 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 { let end := add(s, mload(s)) } 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(o, c)
                        o := add(o, 1)
                        continue
                    }
                    mstore8(o, 0x5c) // "\\".
                    mstore8(add(o, 1), c)
                    o := add(o, 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(o, mload(0x19)) // "\\u00XX".
                    o := add(o, 6)
                    continue
                }
                mstore8(o, 0x5c) // "\\".
                mstore8(add(o, 1), mload(add(c, 8)))
                o := add(o, 2)
            }
            if addDoubleQuotes {
                mstore8(o, 34)
                o := add(1, o)
            }
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(result, sub(o, add(result, 0x20))) // Store the length.
            mstore(0x40, add(o, 0x20)) // Allocate 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 Encodes `s` so that it can be safely used in a URI,
    /// just like `encodeURIComponent` in JavaScript.
    /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
    /// See: https://datatracker.ietf.org/doc/html/rfc2396
    /// See: https://datatracker.ietf.org/doc/html/rfc3986
    function encodeURIComponent(string memory s) internal pure returns (string memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            // Store "0123456789ABCDEF" in scratch space.
            // Uppercased to be consistent with JavaScript's implementation.
            mstore(0x0f, 0x30313233343536373839414243444546)
            let o := add(result, 0x20)
            for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                // If not in `[0-9A-Z-a-z-.!~*'()]`.
                if iszero(and(1, shr(c, 0x47fffffe07fffffe03ff678200000000))) {
                    mstore8(o, 0x25) // '%'.
                    mstore8(add(o, 1), mload(and(shr(4, c), 15)))
                    mstore8(add(o, 2), mload(and(c, 15)))
                    o := add(o, 3)
                    continue
                }
                mstore8(o, c)
                o := add(o, 1)
            }
            mstore(result, sub(o, add(result, 0x20))) // Store the length.
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(0x40, add(o, 0x20)) // Allocate memory.
        }
    }

    /// @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`, where `b` is a null-terminated small string.
    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 m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
            let x := not(or(m, or(b, add(m, and(b, m)))))
            let r := 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))))
            // forgefmt: disable-next-item
            result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
                xor(shr(add(8, r), b), shr(add(8, r), 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 {
            result := mload(0x40) // Grab the free memory pointer.
            mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes).
            mstore(result, 0) // Zeroize the length slot.
            mstore(add(result, 0x1f), packed) // Store the length and bytes.
            mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes.
        }
    }

    /// @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 aLen := mload(a)
            // We don't need to zero right pad the strings,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    or( // Load the length and the bytes of `a` and `b`.
                    shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
                    // `totalLen != 0 && totalLen < 31`. Abuses underflow.
                    // Assumes that the lengths are valid and within the block gas limit.
                    lt(sub(add(aLen, 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 {
            resultA := mload(0x40) // Grab the free memory pointer.
            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 retUnpaddedSize := 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, retUnpaddedSize), 0)
            mstore(retStart, 0x20) // Store the return offset.
            // End the transaction, returning the string.
            return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
        }
    }
}

Settings
{
  "viaIR": true,
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"price_","type":"uint256"},{"internalType":"address","name":"randomiser_","type":"address"},{"internalType":"string","name":"baseURI_","type":"string"},{"internalType":"string[][]","name":"tokenModels_","type":"string[][]"},{"internalType":"enum IDice.TokenRarity","name":"leModelRarity_","type":"uint8"},{"internalType":"uint256","name":"leModelIdx_","type":"uint256"},{"internalType":"uint256","name":"leModelPeriod_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ERC721EnumerableForbiddenBatchMint","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ERC721OutOfBoundsIndex","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"DieRollRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nthRoll","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roll","type":"uint256"}],"name":"DieRolled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"externalURI","type":"string"}],"name":"ExternalURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IDice.TokenRarity","name":"rarity","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"LimitedEditionModelRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MintStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PauseToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PaymentExcessRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomness","type":"uint256"}],"name":"RandomnessIgnored","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"purchaser","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"TokenPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"enum IDice.TokenRarity","name":"rarity","type":"uint8"},{"internalType":"uint248","name":"index","type":"uint248"},{"internalType":"string","name":"name","type":"string"}],"indexed":false,"internalType":"struct IDice.TokenMetadata","name":"metadata","type":"tuple"}],"name":"TokenRevealed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawSucceeded","type":"event"},{"inputs":[],"name":"CALLBACK_GAS_PER_REVEAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_GAS_PER_ROLL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_GAS_REVEAL_OVERHEAD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_GAS_ROLL_OVERHEAD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"__baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"__externalURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"y","type":"uint256"}],"name":"calcRarityFromIndex","outputs":[{"internalType":"enum IDice.TokenRarity","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"getPurchasePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IDice.TokenRarity","name":"rarity","type":"uint8"}],"name":"getRarityName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"getRollPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getTokenDetails","outputs":[{"internalType":"string","name":"uri","type":"string"},{"internalType":"uint256","name":"currentRoll","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getTokenMetadata","outputs":[{"components":[{"internalType":"enum IDice.TokenRarity","name":"rarity","type":"uint8"},{"internalType":"uint248","name":"index","type":"uint248"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct IDice.TokenMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IDice.TokenRarity","name":"rarity","type":"uint8"},{"internalType":"uint240","name":"index","type":"uint240"}],"name":"getTokenModel","outputs":[{"components":[{"internalType":"enum IDice.TokenRarity","name":"rarity","type":"uint8"},{"internalType":"uint248","name":"index","type":"uint248"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct IDice.TokenMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IDice.TokenRarity","name":"rarity","type":"uint8"}],"name":"getTokenModelsByRarity","outputs":[{"components":[{"internalType":"enum IDice.TokenRarity","name":"rarity","type":"uint8"},{"internalType":"uint248","name":"index","type":"uint248"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct IDice.TokenMetadata[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getTotalRolls","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isLimitedEditionModelAvailable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leModelIdx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leModelPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leModelRarity","outputs":[{"internalType":"enum IDice.TokenRarity","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintStartedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isPaused_","type":"bool"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"purchase","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"randomiser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"randomness","type":"uint256"}],"name":"receiveRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"requestInfos","outputs":[{"components":[{"internalType":"enum IDice.RequestKind","name":"kind","type":"uint8"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"internalType":"struct IDice.RequestInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"roll","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"rolls","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"externalURI","type":"string"}],"name":"setExternalURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"start","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenStates","outputs":[{"internalType":"enum IDice.TokenState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610120604052346109d057614d4f8038038061001a81610a6c565b92833981019060e0818303126109d057805160208201519092906001600160a01b03811681036109d05760408301516001600160401b0381116109d05782610063918501610a91565b60608401519093906001600160401b0381116109d057810183601f820112156109d05780519061009a61009583610afc565b610a6c565b9460208087858152019360051b830101918183116109d05760208101935b8385106109d5575050505050608081015160058110156109d05760c060a0830151920151926040966100e988610a6c565b9660048852634469636560e01b602089015261010489610a6c565b9060048252634449434560e01b6020830152610121600054610b3d565b601f8111610986575b506045600090815580527f68747470733a2f2f646963652e616e7972616e642e636f6d2f646963652f3f69600080516020614d2f8339815191525561643d60f01b7f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564558051906001600160401b0382116104525781906101ab600154610b3d565b601f8111610937575b50602090601f83116001146108cf576000926108c4575b50508160011b916000199060031b1c1916176001555b6005875103610880579287878a94976000975b82518910156104e65760058910159485610468576102128a85610b13565b519a8b51156104905760005b8c516001600160f01b038216989089101561047e57610468578c978c6000526002602052610250818c6000209a610b13565b518b51606081019a919290916001600160401b038c11838d1017610452579a8d528e825260208201908152818d019283528a5460009b6801000000000000000082101561043e576001820180825582101561042a578c5260208c209060011b019151906005821015610416575160ff90911660089190911b60ff19161781559051805160019290920191906001600160401b0382116104025781908b6102f68554610b3d565b601f81116103c7575b5050602090601f8311600114610364578c92610359575b50508160011b916000199060031b1c19161790555b6001600160f01b039081169081146103455760010161021e565b634e487b7160e01b88526011600452602488fd5b015190503880610316565b848d52818d209250601f1984168d5b8181106103af5750908460019594939210610396575b505050811b01905561032b565b015160001960f88460031b161c19169055388080610389565b92936020600181928786015181550195019301610373565b602082876103f1945220601f850160051c810191602086106103f8575b601f0160051c0190610b77565b8b386102ff565b90915081906103e4565b634e487b7160e01b8b52604160045260248bfd5b634e487b7160e01b8c52602160045260248cfd5b634e487b7160e01b8d52603260045260248dfd5b634e487b7160e01b8d52604160045260248dfd5b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b50909b505060019099019894506101f4565b885162461bcd60e51b815260206004820152602960248201527f446963653a20526172697479206d7573742068617665206174206c65617374206044820152681bdb99481b5bd9195b60ba1b6064820152608490fd5b9490959689929380519060018060401b03821161045257819061050a600454610b3d565b601f8111610831575b50602090601f83116001146107c9576000926107be575b50508160011b916000199060031b1c1916176004555b8051906001600160401b03821161045257819061055e600554610b3d565b601f811161078b575b50602090601f831160011461072357600092610718575b50508160011b916000199060031b1c1916176005555b331561070257600e8054336001600160a01b0319821681179092556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a360805260a0528160016105f08284610b13565b51511191826106ed575b5050156106995760c05260e05261010052600160ff196013541617601355516141a09081610b8f823960805181818161161201528181611a1e0152611eb8015260a0518181816107f101528181610a1901528181610c1c01528181611001015281816119df0152611e77015260c051818181610ebd0152613984015260e0518181816117a601526139c8015261010051818181611c6a01526139360152f35b835162461bcd60e51b815260206004820152602760248201527f446963653a206d696e2032206d6f64656c7320696e2073616d6520726172697460448201526679206173204c4560c81b6064820152608490fd5b6106f79250610b13565b5151821081866105fa565b631e4fbdf760e01b600052600060045260246000fd5b01519050898061057e565b600560009081528281209350601f198516905b818110610773575090846001959493921061075a575b505050811b01600555610594565b015160001960f88460031b161c1916905589808061074c565b92936020600181928786015181550195019301610736565b6107b89060056000526020600020601f850160051c810191602086106103f857601f0160051c0190610b77565b8a610567565b015190508a8061052a565b600460009081528281209350601f198516905b8181106108195750908460019594939210610800575b505050811b01600455610540565b015160001960f88460031b161c191690558a80806107f2565b929360206001819287860151815501950193016107dc565b600460005261087a907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f850160051c810191602086106103f857601f0160051c0190610b77565b8b610513565b885162461bcd60e51b815260206004820152601b60248201527f446963653a20496e636f6d706c657465207261726974792073657400000000006044820152606490fd5b0151905038806101cb565b600160009081528281209350601f198516905b81811061091f5750908460019594939210610906575b505050811b016001556101e1565b015160001960f88460031b161c191690553880806108f8565b929360206001819287860151815501950193016108e2565b6001600052610980907fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f850160051c810191602086106103f857601f0160051c0190610b77565b386101b4565b600080526109ca90601f0160051c600080516020614d2f833981519152017f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565610b77565b3861012a565b600080fd5b84516001600160401b0381116109d057820183603f820112156109d0576020810151610a0361009582610afc565b916020808085858152019360051b83010101918683116109d05760408201905b838210610a3d5750505090825250602094850194016100b8565b81516001600160401b0381116109d057602091610a618a8480809589010101610a91565b815201910190610a23565b6040519190601f01601f191682016001600160401b0381118382101761045257604052565b81601f820112156109d0578051906001600160401b03821161045257610ac0601f8301601f1916602001610a6c565b92828452602083830101116109d05760005b828110610ae757505060206000918301015290565b80602080928401015182828701015201610ad2565b6001600160401b0381116104525760051b60200190565b8051821015610b275760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b90600182811c92168015610b6d575b6020831014610b5757565b634e487b7160e01b600052602260045260246000fd5b91607f1691610b4c565b818110610b82575050565b60008155600101610b7756fe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a71461035257806302329a291461034d57806306fdde0314610348578063081812fc14610343578063095ea7b31461033e5780630ac1a38b1461033957806318160ddd146103345780631fee7bbc1461032f578063210b9f031461032a57806323b872dd146103255780632f4a2ea1146103205780632f745c591461031b578063336f528a14610316578063350eb906146103115780633ccfd60b1461030c57806342842e0e1461030757806342d3b059146103025780634f6ccce7146102fd5780635c1cd614146102f85780635e31d0a6146102f357806360316801146102ee5780636352211e146102e95780636e34a482146102e45780637081b0aa146102df57806370a08231146102da578063715018a6146102d557806375057e1d146102d057806389e06bcc146102cb5780638bddd88d146102c65780638da5cb5b146102c15780638e21dbf1146102bc57806391d0e5c0146102bc57806395d89b41146102b7578063a035b1fe146102b2578063a22cb465146102ad578063aa3d23df146102a8578063aa9f3eca146102a3578063b187bd261461029e578063b3946ad214610299578063b88d4fde14610294578063be9a65551461028f578063c1e037281461028a578063c59d563314610285578063c87b56dd14610280578063cecaf55f1461027b578063d08b4add14610276578063e0378f4e14610271578063e771811c1461026c578063e985e9c514610267578063eaf95a0d14610262578063efef39a11461025d5763f2fde38b1461025857600080fd5b6120f8565b611e19565b611db8565b611d56565b611ce3565b611c52565b611ac9565b611a9d565b611a7e565b61199f565b611927565b611893565b61182d565b61178e565b611768565b611730565b611708565b611635565b6115fa565b611552565b611534565b61150d565b6114ef565b6114a6565b61144f565b6113e7565b6113bc565b61139f565b6112f7565b6112c8565b611295565b610f6e565b610f4b565b610ee1565b610ea1565b610e6c565b610dc9565b610d88565b610bfc565b610b80565b610b53565b610b3c565b6109f5565b610966565b610870565b610795565b610662565b6105f7565b61051a565b61045c565b61036e565b6001600160e01b031981160361036957565b600080fd5b34610369576020366003190112610369576001600160e01b031960043561039481610357565b167f780e9d630000000000000000000000000000000000000000000000000000000081149081156103ce575b506040519015158152602090f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115610432575b8115610408575b50386103c0565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438610401565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506103fa565b346103695760203660031901126103695760043580151580910361036957610482612f7b565b60135461ff001916600882901b61ff0016176013557f9077d36bc00859b5c3f320310707208543dd35092cb0a0fe117d0c6a558b148b600080a2005b60005b8381106104d15750506000910152565b81810151838201526020016104c1565b906020916104fa815180928185528580860191016104be565b601f01601f1916010190565b9060206105179281815201906104e1565b90565b3461036957600036600319011261036957604051600060045461053c81610c56565b80845290600181169081156105d35750600114610574575b6105708361056481850382610d66565b60405191829182610506565b0390f35b600460009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106105b957509091508101602001610564610554565b9192600181602092548385880101520191019092916105a1565b60ff191660208086019190915291151560051b840190910191506105649050610554565b346103695760203660031901126103695760043561061481612fbd565b50600052600860205260206001600160a01b0360406000205416604051908152f35b600435906001600160a01b038216820361036957565b602435906001600160a01b038216820361036957565b346103695760403660031901126103695761067b610636565b6024359061068882612fbd565b33151580610782575b8061073e575b610710578261070e936106e6926001600160a01b0380861691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a46000526008602052604060002090565b906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b005b7fa9fbf51f000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b5060ff61077a33610762846001600160a01b03166000526009602052604060002090565b906001600160a01b0316600052602052604060002090565b541615610697565b50336001600160a01b0382161415610691565b34610369576020366003190112610369576004358061c350029061c35082040361086b5760406107c76107e5926121f8565b81518093819263085868e960e11b8352600483019190602083019252565b03816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa80156108665761057091600091610836575b506040519081529081906020820190565b610858915060403d60401161085f575b6108508183610d66565b810190612233565b5038610825565b503d610846565b612249565b6121a7565b34610369576000366003190112610369576020600c54604051908152f35b60043590600582101561036957565b634e487b7160e01b600052602160045260246000fd5b600511156108bd57565b61089d565b9060058210156108bd5752565b9060606040610517936108e38482516108c2565b6001600160f81b03602082015116602085015201519181604082015201906104e1565b602081016020825282518091526040820191602060408360051b8301019401926000915b83831061093957505050505090565b9091929394602080610957600193603f1986820301875289516108cf565b9701930193019193929061092a565b346103695760203660031901126103695761097f61088e565b60058110156108bd576000526002602052604060002080546109a08161226e565b916109ae6040519384610d66565b818352602083019060005260206000206000915b8383106109d757604051806105708782610906565b600260206001926109e785612292565b8152019201920191906109c2565b3461036957604036600319011261036957600435602435610a406001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633146122d8565b610a54826000526011602052604060002090565b91610a60835460ff1690565b835460ff19168455610a7181611726565b60018103610ab1575050610aac610aa6600161070e940192610a9b81610a968661233b565b6131b9565b600052602060002090565b9161233b565b613080565b80610abd600292611726565b03610ad25750610aac600161070e930161233b565b60405191825291507fc856f5dd60efc0d8ff81e7d44ad79d2f66c6e205f48321258f4c4fa9b40d879490602090a2005b6060906003190112610369576004356001600160a01b038116810361036957906024356001600160a01b0381168103610369579060443590565b346103695761070e610b4d36610b02565b91612386565b34610369576020366003190112610369576020610b71600435612530565b610b7e60405180926108c2565bf35b3461036957604036600319011261036957610b99610636565b6001600160a01b0360243591610bae8161298f565b831015610be45716600052600a602052604060002090600052602052610570604060002054604051918291829190602083019252565b63295f44f760e21b6000521660045260245260446000fd5b346103695760003660031901126103695760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b634e487b7160e01b600052600060045260246000fd5b90600182811c92168015610c86575b6020831014610c7057565b634e487b7160e01b600052602260045260246000fd5b91607f1691610c65565b60009291815491610ca083610c56565b8083529260018116908115610cf65750600114610cbc57505050565b60009081526020812093945091925b838310610cdc575060209250010190565b600181602092949394548385870101520191019190610ccb565b915050602093945060ff929192191683830152151560051b010190565b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff821117610d4557604052565b610d13565b6060810190811067ffffffffffffffff821117610d4557604052565b90601f8019910116810190811067ffffffffffffffff821117610d4557604052565b3461036957600036600319011261036957610570604051610db581610dae816000610c90565b0382610d66565b6040519182916020835260208301906104e1565b3461036957600036600319011261036957610de2612f7b565b47600080808084335af1610df4612584565b5015610e28576040519081527f0d844f1a03bee48636780fe86fa98a7dd80250e1739d2b598e5c1ae1c021b28d60203392a2005b606460405162461bcd60e51b815260206004820152601560248201527f446963653a207769746864726177206661696c656400000000000000000000006044820152fd5b346103695761070e610e7d36610b02565b9060405192610e8d602085610d66565b60008452610e9c838383612386565b613418565b34610369576000366003190112610369576020604051610b7e817f00000000000000000000000000000000000000000000000000000000000000006108c2565b3461036957602036600319011261036957600435600c54811015610f3257600c6000527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70154604051908152602090f35b63295f44f760e21b600052600060045260245260446000fd5b3461036957600036600319011261036957602060ff601354166040519015158152f35b60203660031901126103695760043567ffffffffffffffff8111610369573660238201121561036957806004013567ffffffffffffffff8111610369576024820191602436918360051b01011161036957610fd160ff60135460081c16156125b4565b610fe2610fdd826121bd565b6121f8565b6040805163085868e960e11b8152600481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169181602481855afa90811561086657600091611275575b50611045813410156125ff565b803411611215575b60005b84811061116e5750916020916110ac936110694261220a565b906040518096819582947f1f53cf040000000000000000000000000000000000000000000000000000000084526004840160209093929193604081019481520152565b03925af19081156108665760009161113f575b506110f86110cb6117c9565b600281526110da368587612766565b60208201526110f3836000526011602052604060002090565b6127c9565b60005b82811061110457005b808261111360019386886126b1565b357ffa76b3955fb2015dafb3312a1afed625a3705dfff7e20a905c803c16a058d801600080a3016110fb565b611161915060203d602011611167575b6111598183610d66565b810190612757565b386110bf565b503d61114f565b8061119e61119761118b6111856001958a8c6126b1565b35612fbd565b6001600160a01b031690565b33146122d8565b6111db60026111cc6111c56111b4858b8d6126b1565b35600052600f602052604060002090565b5460ff1690565b6111d581611726565b146126c1565b80156112105761120a6111ef82888a6126b1565b356112036111fc8461264a565b898b6126b1565b351061270c565b01611050565b61120a565b61123860008080806112278634612659565b335af1611232612584565b50612666565b6112428134612659565b60405190815233907f63e351cd0651c5ddd4bcc26ac590387707c971a4136303f334540176aaffa95390602090a261104d565b61128e915060403d60401161085f576108508183610d66565b5038611038565b34610369576020366003190112610369576105706112b46004356128a2565b6040519182916020835260208301906108cf565b346103695760203660031901126103695760206112e6600435612fbd565b6001600160a01b0360405191168152f35b3461036957600036600319011261036957604051600060015461131981610c56565b80845290600181169081156105d35750600114611340576105708361056481850382610d66565b600160009081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b80821061138557509091508101602001610564610554565b91926001816020925483858801015201910190929161136d565b3461036957600036600319011261036957602060405161c3508152f35b346103695760203660031901126103695760206113df6113da610636565b61298f565b604051908152f35b3461036957600036600319011261036957611400612f7b565b60006001600160a01b03600e5473ffffffffffffffffffffffffffffffffffffffff198116600e55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461036957602036600319011261036957610570610db561146e61088e565b612b05565b634e487b7160e01b600052603260045260246000fd5b80548210156114a15760005260206000200190600090565b611473565b346103695760403660031901126103695760043560243590600052601060205260406000208054821015610369576020916114e091611489565b90549060031b1c604051908152f35b34610369576000366003190112610369576020601254604051908152f35b346103695760003660031901126103695760206001600160a01b03600e5416604051908152f35b34610369576000366003190112610369576020604051620493e08152f35b3461036957600036600319011261036957604051600060055461157481610c56565b80845290600181169081156105d3575060011461159b576105708361056481850382610d66565b600560009081527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0939250905b8082106115e057509091508101602001610564610554565b9192600181602092548385880101520191019092916115c8565b346103695760003660031901126103695760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346103695760403660031901126103695761164e610636565b6024358015158103610369576001600160a01b0382169182156116da57816116996116aa923360005260096020526040600020906001600160a01b0316600052602052604060002090565b9060ff801983541691151516179055565b60405190151581527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b827f5b08ba180000000000000000000000000000000000000000000000000000000060005260045260246000fd5b34610369576000366003190112610369576020604051620249f08152f35b600311156108bd57565b3461036957602036600319011261036957600435600052600f602052602060ff604060002054166040519061176481611726565b8152f35b3461036957600036600319011261036957602060ff60135460081c166040519015158152f35b346103695760003660031901126103695760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b604051906117d8604083610d66565b565b67ffffffffffffffff8111610d4557601f01601f191660200190565b929192611802826117da565b916118106040519384610d66565b829481845281830111610369578281602093846000960137010152565b3461036957608036600319011261036957611846610636565b61184e61064c565b906044356064359267ffffffffffffffff841161036957366023850112156103695761188761070e9436906024816004013591016117f6565b92610e9c838383612386565b34610369576000366003190112610369576118ac612f7b565b6012546118e357426012557f57fd5d9258bc5040104b1a0db17596ff674d188a2a5e45a80ad7c035c848adfb6020604051428152a1005b606460405162461bcd60e51b815260206004820152601a60248201527f446963653a206d696e7420616c726561647920737461727465640000000000006044820152fd5b346103695760203660031901126103695760043561194481612b71565b906000526010602052604060002090815491611961831515612513565b600019830192831161086b576119959261197a91611489565b90549060031b1c6040519283926040845260408401906104e1565b9060208301520390f35b346103695760203660031901126103695760043580620249f002620249f08104820361086b5760406107c76119d3926121f8565b03816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa80156108665761057092611a4892600092611a58575b50611a43907f0000000000000000000000000000000000000000000000000000000000000000906121e5565b612226565b6040519081529081906020820190565b611a43919250611a769060403d60401161085f576108508183610d66565b509190611a17565b3461036957602036600319011261036957610570610db5600435612b71565b346103695760203660031901126103695760043560005260106020526020604060002054604051908152f35b346103695760203660031901126103695760043567ffffffffffffffff8111610369573660238201121561036957611b0b9036906024816004013591016117f6565b611b13612f7b565b805167ffffffffffffffff8111610d4557611b3881611b33600054610c56565b612e6c565b6020601f8211600114611bab5791611b8c82611b9b937f637f3fe47415bd9a869d5eec4d04a98a500a05fab915b6bea839c0d57831645795600091611ba0575b508160011b916000199060031b1c19161790565b60005560405191829182610506565b0390a1005b905083015138611b78565b60008052601f198216907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639160005b818110611c3a5750927f637f3fe47415bd9a869d5eec4d04a98a500a05fab915b6bea839c0d578316457949260019282611b9b9610611c21575b5050811b01600055610564565b84015160001960f88460031b161c191690553880611c14565b91926020600181928689015181550194019201611bda565b346103695760003660031901126103695760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b9060208252602060808160608501938051611ca781611726565b8287015201519360408082015284518094520192019060005b818110611ccd5750505090565b8251845260209384019390920191600101611cc0565b346103695760203660031901126103695760043560606020604051611d0781610d29565b60008152015260005260116020526105706040600020611d45600160405192611d2f84610d29565b60ff815416611d3d81611726565b84520161233b565b602082015260405191829182611c8d565b3461036957604036600319011261036957602060ff611dac611d76610636565b6001600160a01b03611d8661064c565b9116600052600984526040600020906001600160a01b0316600052602052604060002090565b54166040519015158152f35b3461036957604036600319011261036957611dd161088e565b6024356001600160f01b038116810361036957611dec612865565b5060058210156108bd57611e136112b4916105709360005260026020526040600020612886565b50612292565b602036600319011261036957600435601254156120b457611e4260ff60135460081c16156125b4565b611e4a613923565b611e56610fdd826121d0565b6040805163085868e960e11b81526004810183905292916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169184602481855afa93841561086657600094612092575b50611edd84611a437f0000000000000000000000000000000000000000000000000000000000000000866121e5565b91611eea833410156125ff565b823411612032575b611efd600c54612218565b94611f0785612f35565b9560005b868110611fe657505091602091611f25936110694261220a565b03925af190811561086657600091611fc7575b50611f62611f446117c9565b600181528560208201526110f3836000526011602052604060002090565b60005b838110611f6e57005b80611f85611f7e60019388612f67565b5133613a34565b611f8f8187612f67565b5160405185815233919085907f6a07643617236b9185b93ee3100548cc2f3d46f2188b50ef2f7b911158b1ba3e90602090a401611f65565b611fe0915060203d602011611167576111598183610d66565b38611f38565b80611ff360019284612226565b611ffd828b612f67565b5261202c61201f61200e838c612f67565b51600052600f602052604060002090565b805460ff19166001179055565b01611f0b565b61205560008080806120448834612659565b335af161204f612584565b50612eea565b61205f8334612659565b60405190815233907f63e351cd0651c5ddd4bcc26ac590387707c971a4136303f334540176aaffa95390602090a2611ef2565b6120ac91945060403d60401161085f576108508183610d66565b509238611eae565b606460405162461bcd60e51b815260206004820152601660248201527f446963653a206d696e74206e6f742073746172746564000000000000000000006044820152fd5b34610369576020366003190112610369576001600160a01b03612119610636565b612121612f7b565b168015612178576001600160a01b03600e548273ffffffffffffffffffffffffffffffffffffffff19821617600e55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b634e487b7160e01b600052601160045260246000fd5b908161c350029161c35083040361086b57565b9081620249f00291620249f083040361086b57565b8181029291811591840414171561086b57565b620493e0019081620493e01161086b57565b90601e820180921161086b57565b906001820180921161086b57565b9190820180921161086b57565b9190826040910312610369576020825192015190565b6040513d6000823e3d90fd5b60058110156108bd576000526002602052604060002090565b67ffffffffffffffff8111610d455760051b60200190565b60058210156108bd5752565b906001604080516122a281610d4a565b6122d4819580546122b660ff821685612286565b60081c60208401526122cd84518096819301610c90565b0384610d66565b0152565b156122df57565b606460405162461bcd60e51b815260206004820152601460248201527f446963653a20696e76616c69642073656e6465720000000000000000000000006044820152fd5b9061232d81611726565b60ff80198354169116179055565b906040519182815491828252602082019060005260206000209260005b81811061236d5750506117d892500383610d66565b8454835260019485019487945060209093019201612358565b9190916001600160a01b0383169081156124fd576001600160a01b03916000948486526006602052846123c4604088206001600160a01b0390541690565b92336124ed575b85841697881580156124ba575b6123f5856001600160a01b03166000526007602052604060002090565b60018154019055612414856106e6866000526006602052604060002090565b83838b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8580a4156124a45761244983613e6c565b508703612494575b5050501680830361246157505050565b7f64283d7b0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b61249d91613ece565b3884612451565b888214612449576124b58386613db2565b612449565b6124c384613b9c565b6124e0866001600160a01b03166000526007602052604060002090565b80546000190190556123d8565b6124f8823386613f60565b6123cb565b633250574960e11b600052600060045260246000fd5b1561251a57565b634e487b7160e01b600052600160045260246000fd5b61253e620f42408210612513565b6000906064811015612551575050600490565b6113ec811015612562575050600390565b62014c08811015612574575050600290565b620668a011156105175750600190565b3d156125af573d90612595826117da565b916125a36040519384610d66565b82523d6000602084013e565b606090565b156125bb57565b606460405162461bcd60e51b815260206004820152601860248201527f446963653a20636f6e74726163742069732070617573656400000000000000006044820152fd5b1561260657565b606460405162461bcd60e51b815260206004820152601a60248201527f446963653a20696e73756666696369656e74207061796d656e740000000000006044820152fd5b60001981019190821161086b57565b9190820391821161086b57565b1561266d57565b606460405162461bcd60e51b815260206004820152601360248201527f446963653a20726566756e64206661696c6564000000000000000000000000006044820152fd5b91908110156114a15760051b0190565b156126c857565b606460405162461bcd60e51b815260206004820152601860248201527f446963653a20746f6b656e206e6f742072657665616c656400000000000000006044820152fd5b1561271357565b606460405162461bcd60e51b815260206004820152601760248201527f446963653a20756e736f7274656420746f6b656e4964730000000000000000006044820152fd5b90816020910312610369575190565b9291906127728161226e565b936127806040519586610d66565b602085838152019160051b810192831161036957905b8282106127a257505050565b8135815260209182019101612796565b8181106127bd575050565b600081556001016127b2565b60016020916127e284516127dc81611726565b82612323565b019101519081519167ffffffffffffffff8311610d4557680100000000000000008311610d45576020908254848455808510612848575b500190600052602060002060005b8381106128345750505050565b600190602084519401938184015501612827565b61285f9084600052858460002091820191016127b2565b38612819565b6040519061287282610d4a565b606060408360008152600060208201520152565b80548210156114a15760005260206000209060011b0190600090565b6128aa612865565b5060005260036020526040600020604051906128c582610d4a565b549060ff82161515815260208101906128e460ff8460081c1683612286565b604081019260101c83525115612925576105179161291f612911611e13935161290c816108b3565b612255565b91516001600160f01b031690565b90612886565b608460405162461bcd60e51b815260206004820152602160248201527f446963653a20546f6b656e206d65746164617461206e6f742061737369676e6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b031680156129af57600052600760205260406000205490565b7f89c62b6400000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b604051906129ed604083610d66565b600982527f4c6567656e6461727900000000000000000000000000000000000000000000006020830152565b60405190612a28604083610d66565b600482527f45706963000000000000000000000000000000000000000000000000000000006020830152565b60405190612a63604083610d66565b600482527f52617265000000000000000000000000000000000000000000000000000000006020830152565b60405190612a9e604083610d66565b600882527f556e636f6d6d6f6e0000000000000000000000000000000000000000000000006020830152565b60405190612ad9604083610d66565b600682527f436f6d6d6f6e00000000000000000000000000000000000000000000000000006020830152565b612b0e816108b3565b80612b1c5750610517612aca565b612b25816108b3565b60018103612b365750610517612a8f565b612b3f816108b3565b60028103612b505750610517612a54565b80612b5c6003926108b3565b03612b6957610517612a19565b6105176129de565b612b7a81612fbd565b5080600052600f60205260406000205460ff16612b9681611726565b600214612ba2906126c1565b612bab816128a2565b90612bb581613f19565b91604051809360208201612bc8906134b4565b808251602081940191612bda926104be565b0103601f1981018452612bed9084610d66565b8051612bf8816108b3565b612c01816108b3565b612c0a90613f19565b906020810151612c20906001600160f81b031690565b6001600160f81b0316612c3290613f19565b91612c3d83826135c1565b92612c479161366b565b92612c5190613f19565b928151612c5d816108b3565b612c6690612b05565b91604001519260405195869560208701612ca4906016907f7b226e616d65223a224f6e636861696e2044696520230000000000000000000081520190565b612cad916135aa565b7f222c226465736372697074696f6e223a225265726f6c6c20796f75722064696381527f65207573696e672076657269666961626c652072616e646f6d6e657373206f6e60208201527f20646963652e616e7972616e642e636f6d222c2265787465726e616c5f75726c604082015262111d1160e91b6060820152606301612d34916135aa565b7f222c22696d616765223a220000000000000000000000000000000000000000008152600b01612d63916135aa565b7f222c22616e696d6174696f6e5f75726c223a22000000000000000000000000008152601301612d92916135aa565b7f222c2261747472696275746573223a205b7b2274726169745f74797065223a2281527f526172697479222c2276616c7565223a220000000000000000000000000000006020820152603101612de7916135aa565b7f227d2c207b2274726169745f74797065223a224d6f64656c222c2276616c7565815262111d1160e91b6020820152602301612e22916135aa565b7f227d5d7d00000000000000000000000000000000000000000000000000000000815260040103601f1981018252612e5a9082610d66565b612e639061405b565b61051790613716565b90601f8211612e79575050565b6117d891600080526020600020906020601f840160051c83019310612ea6575b601f0160051c01906127b2565b9091508190612e99565b9190601f8111612ebf57505050565b6117d8926000526020600020906020601f840160051c83019310612ea657601f0160051c01906127b2565b15612ef157565b606460405162461bcd60e51b815260206004820152601360248201527f446963653a20526566756e64206661696c6564000000000000000000000000006044820152fd5b90612f3f8261226e565b612f4c6040519182610d66565b8281528092612f5d601f199161226e565b0190602036910137565b80518210156114a15760209160051b010190565b6001600160a01b03600e54163303612f8f57565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b8060005260066020526001600160a01b0360406000205416908115612fe0575090565b637e27328960e01b60005260045260246000fd5b15612ffb57565b606460405162461bcd60e51b815260206004820152601960248201527f446963653a20696e76616c696420746f6b656e207374617465000000000000006044820152fd5b9081549168010000000000000000831015610d4557826130679160016117d895018155611489565b90919082549060031b91821b91600019901b1916179055565b919060005b835181101561317e578061309b60019286612f67565b516130c8600260ff6130b784600052600f602052604060002090565b54166130c281611726565b14612ff4565b7f55a80d8c44b8f38d921a310dd9d3f9966452d3468ef1ebfb93adae63ce5bcd3861312e61312960405161311f816131118a886020840160209093929193604081019481520152565b03601f198101835282610d66565b6020815191012090565b613bed565b61314b81613146856000526010602052604060002090565b61303f565b613168613162846000526010602052604060002090565b5461264a565b604080519182526020820192909252a201613085565b50509050565b9060016080610517936020815283546131a36020830160ff83166108c2565b60081c6040820152606080820152019101610c90565b919060005b835181101561317e57806131d460019286612f67565b516131f9836131f06111c584600052600f602052604060002090565b6130c281611726565b61321d61321082600052600f602052604060002090565b805460ff19166002179055565b7f6c9cd8284a3a8f9758cddfea0e2b2fa713d646f3ea6a14cc11896a821499bda96132bb6132ae61326960405161311f816131118b896020840160209093929193604081019481520152565b61327a61327582613c1b565b612530565b9061328482612255565b805490918982036132c45750506132a96000925b6001600160f01b0384169088613ce2565b612886565b5060405191829182613184565b0390a2016131be565b6132a9916132da6132df92600052602060002090565b613c4c565b92613298565b90816020910312610369575161051781610357565b90926001600160a01b03608093816105179796168452166020830152604082015281606082015201906104e1565b9190823b61333557505050565b61335a916020916040519384928392630a85bd0160e11b8452600033600486016132fa565b038160006001600160a01b0387165af1600091816133e7575b506133af5750613381612584565b80519190826133a857633250574960e11b6000526001600160a01b03821660045260246000fd5b9050602001fd5b6001600160e01b0319630a85bd0160e11b9116036133ca5750565b633250574960e11b6000526001600160a01b031660045260246000fd5b61340a91925060203d602011613411575b6134028183610d66565b8101906132e5565b9038613373565b503d6133f8565b909291833b613428575b50505050565b60209161344a6040519485938493630a85bd0160e11b855233600486016132fa565b038160006001600160a01b0387165af160009181613493575b506134715750613381612584565b6001600160e01b0319630a85bd0160e11b9116036133ca575038808080613422565b6134ad91925060203d602011613411576134028183610d66565b9038613463565b90600091600054906134c582610c56565b916001811690811561352a57506001146134dd575050565b600080805292935090917f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8382106135165750500190565b600181602092548486015201910190613509565b60ff1916825250811515909102019150565b6000929181549161354c83610c56565b9260018116908115613597575060011461356557505050565b909192935060005260206000206000905b8382106135835750500190565b600181602092548486015201910190613576565b60ff191683525050811515909102019150565b906135bd602092828151948592016104be565b0190565b600460016117d892949394826040519687926135e0602085018661353c565b7f696d672f00000000000000000000000000000000000000000000000000000000815261361682518093602087850191016104be565b01602f60f81b838201526136348251809360206005850191016104be565b01017f2e706e6700000000000000000000000000000000000000000000000000000000838201520301601b19810185520183610d66565b600460016117d892949394600560405196879261368b602085018661353c565b7f676c74662f00000000000000000000000000000000000000000000000000000081526136c182518093602087850191016104be565b01602f60f81b838201526136df8251809360206006850191016104be565b01017f2e676c6200000000000000000000000000000000000000000000000000000000838201520301601b19810185520183610d66565b906117d8603d60405180947f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000602083015261375a81518092602086860191016104be565b81010301601f198101845283610d66565b9092919261386e57825160058110156108bd57602084015160081b60ff191660ff90911617815560409290920151805190926001019067ffffffffffffffff8111610d45576137c4816137be8454610c56565b84612eb0565b6020601f82116001146138055781906137f69394956000926137fa575b50508160011b916000199060031b1c19161790565b9055565b0151905038806137e1565b601f1982169061381a84600052602060002090565b9160005b8181106138565750958360019596971061383d575b505050811b019055565b015160001960f88460031b161c19169055388080613833565b9192602060018192868b01518155019401920161381e565b610c40565b805480156138f857600019019061388a8282612886565b61386e5780600060019255016138a08154610c56565b90816138ab57505055565b601f82116001146138bf5760009055505b55565b6138e76138bc926001601f6138d985600052602060002090565b920160051c820191016127b2565b600081815260208120918190559055565b634e487b7160e01b600052603160045260246000fd5b602090939291936122d48160408101966108c2565b60135460ff16156117d85761395b6012547f000000000000000000000000000000000000000000000000000000000000000090612226565b42106117d8577fd1dc84168a0cf4a73527c9d58ff29ec6e1e0691a0dbc44df352750933052a17d7f00000000000000000000000000000000000000000000000000000000000000006139ac81612255565b90613a116139c6611e136139c0855461264a565b85612886565b7f00000000000000000000000000000000000000000000000000000000000000006001600160f81b03811660208301529390613a0c90613a068684612886565b9061376b565b613873565b613a2060ff1960135416601355565b613a2f6040519283928361390e565b0390a1565b9060405190613a44602083610d66565b600082526001600160a01b03831680156124fd576000908282526006602052613a78604083206001600160a01b0390541690565b906001600160a01b03821680159384159485613b69575b613aac896001600160a01b03166000526007602052604060002090565b60018154019055613acb896106e6896000526006602052604060002090565b8684847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8580a415613b5357613b0086613e6c565b5003613b44575b50613b15576117d892613328565b7f73c6ac6e00000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b613b4e8386613ece565b613b07565b818314613b0057613b648685613db2565b613b00565b613b7287613b9c565b613b8f856001600160a01b03166000526007602052604060002090565b8054600019019055613a8f565b613bb0906000526008602052604060002090565b805473ffffffffffffffffffffffffffffffffffffffff19169055565b8115613bd7570690565b634e487b7160e01b600052601260045260246000fd5b600060015b15613c08575b5060008181526020812090613bf2565b600319811015613bf85790506006900690565b600060015b15613c36575b5060008181526020812090613c20565b6209c3bf19811015613c2657620f424091500690565b908015613bd757806000190619600060015b15613c74575b5060008381526020812090613c5e565b81811015613c645790506105179250613bcd565b90613ca281511515839060ff801983541691151516179055565b602081015160058110156108bd57613ccc61ffff9184549061ff009060081b169061ff0019161790565b918284556040821991015160101b169116179055565b9182600052600360205260ff60406000205416613d48576117d892613d33613d4392613d2360405195613d16606088610d66565b6001875260208701612286565b6001600160f01b03166040850152565b6000526003602052604060002090565b613c88565b608460405162461bcd60e51b815260206004820152602560248201527f446963653a20546f6b656e206d6574616461746120616c72656164792061737360448201527f69676e65640000000000000000000000000000000000000000000000000000006064820152fd5b600091613e0a6138bc9284613df0613dc98361298f565b94808352600b6020526040832054868103613e19575b50600052600b602052604060002090565b556001600160a01b0316600052600a602052604060002090565b90600052602052604060002090565b613e656001600160a01b038616808652600a602052604086208987526020526040862054908652600a60205260408620838752602052806040872055600052600b602052604060002090565b5538613ddf565b600c5481600052600d602052604060002055600c5468010000000000000000811015610d455760018101600c556000600c548210156114a157600c90527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70155565b90613ed88261298f565b60001981019290831161086b576001600160a01b0316600052600a60205260406000208260005260205280604060002055600052600b602052604060002055565b90604051600a608082019360a0830160405260008552935b6000190193603082820601855304928315613f4e57600a90613f31565b809350608091030191601f1901918252565b919091613f7e6001600160a01b0384168015159081613fe357501590565b613f8757505050565b6001600160a01b0316613fa857637e27328960e01b60005260045260246000fd5b7f177e802f000000000000000000000000000000000000000000000000000000006000526001600160a01b0390911660045260245260446000fd5b6001600160a01b03841680821492508215614024575b50811561400557501590565b90508360005260086020526001600160a01b0360406000205416141590565b909150600052600960205260ff614052866040600020906001600160a01b0316600052602052604060002090565b54169038613ff9565b8051606092918161406a575050565b9092506003600284010460021b90604051937f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106707f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f5260208501918386019060208201926020818301019460046003875194600089525b0191603f8351818160121c16516000538181600c1c1651600153818160061c16516002531651600353600051815201908582101561412c576004906003906140e9565b50935060407f3d3d0000000000000000000000000000000000000000000000000000000000009360039360009752016040520660020482035252825256fea2646970667358221220ec0f9fe603f47c29f7103b48e5135e04137d46cb324dbe1fa698ec8b558cd8b964736f6c634300081a0033290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563000000000000000000000000000000000000000000000000000ef2273c1b08000000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000000036697066733a2f2f516d57506944673134596350374e7241736e384b5575734b464169454e795031784752367546647156714e4e6e6d2f00000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000fc00000000000000000000000000000000000000000000000000000000000001b2000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000026c0000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000740000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000008c000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000000000000000000000000098000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000b400000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000bc00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000cc00000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000d800000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000e400000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000ec0000000000000000000000000000000000000000000000000000000000000000f416c756d696e69756d20426c61636b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e416c756d696e69756d20426c7565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f416c756d696e69756d20477265656e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014416c756d696e69756d204c6967687420426c75650000000000000000000000000000000000000000000000000000000000000000000000000000000000000010416c756d696e69756d204f72616e6765000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010416c756d696e69756d20507572706c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d416c756d696e69756d20526564000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010416c756d696e69756d2053696c766572000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010416c756d696e69756d2059656c6c6f7700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b436173696e6f20426c7565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c436173696e6f20477265656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d436173696e6f20507572706c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a436173696e6f2052656400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d436173696e6f2059656c6c6f7700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e477261666669746920426c61636b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d477261666669746920426c756500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e477261666669746920477265656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4772616666697469204f72616e67650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d47726166666974692050696e6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010477261666669746920507572706c652000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c4772616666697469205265640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4772616666697469205768697465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4a75737420426c61636b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000094a75737420426c75650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4a75737420477265656e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4a757374204f72616e676500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000094a7573742050696e6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4a75737420507572706c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084a75737420526564000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4a75737420576869746500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4a7573742059656c6c6f77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b506978656c20426c61636b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a506978656c20426c756500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b506978656c20477265656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c506978656c204f72616e67650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b506978656c2050696e6b20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c506978656c20507572706c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009506978656c205265640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c506978656c205768697465200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d506978656c2059656c6c6f772000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000740000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000008c000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000000000000000000000000098000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000007416e7972616e64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007426974636f696e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005436c75627300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000094461726b20576f6f64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084469616d6f6e64730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008457468657265756d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006486561727473000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4b616e6a6920426c756500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4b616e6a6920477265656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4b616e6a692050696e6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c4b616e6a692059656c6c6f77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044b6977690000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000114c6561677565206f6620456e74726f707900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000094d617a6520426c75650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4d617a6520477265656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d617a6520526564000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4d617a652059656c6c6f7700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064f72616e6765000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044f74746f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000752616e64616d7500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b526f6d616e2053746f6e6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065363726f6c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065370616465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001454686520436972636c652047616d6520426c7565000000000000000000000000000000000000000000000000000000000000000000000000000000000000001554686520436972636c652047616d6520477265656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000001354686520436972636c652047616d652052656400000000000000000000000000000000000000000000000000000000000000000000000000000000000000001654686520436972636c652047616d652059656c6c6f7700000000000000000000000000000000000000000000000000000000000000000000000000000000000a57617465726d656c6f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004576f6f64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006c00000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000074000000000000000000000000000000000000000000000000000000000000000064172726f77730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642696e61727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005427261696e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642726f6e7a650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4469636553746174696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007466c6f77657273000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008466f6f7462616c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000547686f7374000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c476f6c64656e20436c7562730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f476f6c64656e204469616d6f6e64730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d476f6c64656e2048656172747300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d476f6c64656e205370616465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044c65676f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054e617a6172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000550617274790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009506f77657242616c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a52617265205761677975000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012526f6d616e205768697465204d6172626c650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5469632d7461632d746f65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000859696e6759616e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000005436c6f636b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001049276d207761746368696e6720796f750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074f442d30363958000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012526f6d616e20426c61636b204d6172626c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005527562696b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000653696c7665720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000753796e6368726f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e5468652045706963204368656573652043756265206f6620457465726e616c6c79204167656420466f7274756e6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000075472617070656400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b576861632d412d4d6f6c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e54686520476f6c64656e20446965000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a71461035257806302329a291461034d57806306fdde0314610348578063081812fc14610343578063095ea7b31461033e5780630ac1a38b1461033957806318160ddd146103345780631fee7bbc1461032f578063210b9f031461032a57806323b872dd146103255780632f4a2ea1146103205780632f745c591461031b578063336f528a14610316578063350eb906146103115780633ccfd60b1461030c57806342842e0e1461030757806342d3b059146103025780634f6ccce7146102fd5780635c1cd614146102f85780635e31d0a6146102f357806360316801146102ee5780636352211e146102e95780636e34a482146102e45780637081b0aa146102df57806370a08231146102da578063715018a6146102d557806375057e1d146102d057806389e06bcc146102cb5780638bddd88d146102c65780638da5cb5b146102c15780638e21dbf1146102bc57806391d0e5c0146102bc57806395d89b41146102b7578063a035b1fe146102b2578063a22cb465146102ad578063aa3d23df146102a8578063aa9f3eca146102a3578063b187bd261461029e578063b3946ad214610299578063b88d4fde14610294578063be9a65551461028f578063c1e037281461028a578063c59d563314610285578063c87b56dd14610280578063cecaf55f1461027b578063d08b4add14610276578063e0378f4e14610271578063e771811c1461026c578063e985e9c514610267578063eaf95a0d14610262578063efef39a11461025d5763f2fde38b1461025857600080fd5b6120f8565b611e19565b611db8565b611d56565b611ce3565b611c52565b611ac9565b611a9d565b611a7e565b61199f565b611927565b611893565b61182d565b61178e565b611768565b611730565b611708565b611635565b6115fa565b611552565b611534565b61150d565b6114ef565b6114a6565b61144f565b6113e7565b6113bc565b61139f565b6112f7565b6112c8565b611295565b610f6e565b610f4b565b610ee1565b610ea1565b610e6c565b610dc9565b610d88565b610bfc565b610b80565b610b53565b610b3c565b6109f5565b610966565b610870565b610795565b610662565b6105f7565b61051a565b61045c565b61036e565b6001600160e01b031981160361036957565b600080fd5b34610369576020366003190112610369576001600160e01b031960043561039481610357565b167f780e9d630000000000000000000000000000000000000000000000000000000081149081156103ce575b506040519015158152602090f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115610432575b8115610408575b50386103c0565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438610401565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506103fa565b346103695760203660031901126103695760043580151580910361036957610482612f7b565b60135461ff001916600882901b61ff0016176013557f9077d36bc00859b5c3f320310707208543dd35092cb0a0fe117d0c6a558b148b600080a2005b60005b8381106104d15750506000910152565b81810151838201526020016104c1565b906020916104fa815180928185528580860191016104be565b601f01601f1916010190565b9060206105179281815201906104e1565b90565b3461036957600036600319011261036957604051600060045461053c81610c56565b80845290600181169081156105d35750600114610574575b6105708361056481850382610d66565b60405191829182610506565b0390f35b600460009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106105b957509091508101602001610564610554565b9192600181602092548385880101520191019092916105a1565b60ff191660208086019190915291151560051b840190910191506105649050610554565b346103695760203660031901126103695760043561061481612fbd565b50600052600860205260206001600160a01b0360406000205416604051908152f35b600435906001600160a01b038216820361036957565b602435906001600160a01b038216820361036957565b346103695760403660031901126103695761067b610636565b6024359061068882612fbd565b33151580610782575b8061073e575b610710578261070e936106e6926001600160a01b0380861691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a46000526008602052604060002090565b906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b005b7fa9fbf51f000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b5060ff61077a33610762846001600160a01b03166000526009602052604060002090565b906001600160a01b0316600052602052604060002090565b541615610697565b50336001600160a01b0382161415610691565b34610369576020366003190112610369576004358061c350029061c35082040361086b5760406107c76107e5926121f8565b81518093819263085868e960e11b8352600483019190602083019252565b03816001600160a01b037f0000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe165afa80156108665761057091600091610836575b506040519081529081906020820190565b610858915060403d60401161085f575b6108508183610d66565b810190612233565b5038610825565b503d610846565b612249565b6121a7565b34610369576000366003190112610369576020600c54604051908152f35b60043590600582101561036957565b634e487b7160e01b600052602160045260246000fd5b600511156108bd57565b61089d565b9060058210156108bd5752565b9060606040610517936108e38482516108c2565b6001600160f81b03602082015116602085015201519181604082015201906104e1565b602081016020825282518091526040820191602060408360051b8301019401926000915b83831061093957505050505090565b9091929394602080610957600193603f1986820301875289516108cf565b9701930193019193929061092a565b346103695760203660031901126103695761097f61088e565b60058110156108bd576000526002602052604060002080546109a08161226e565b916109ae6040519384610d66565b818352602083019060005260206000206000915b8383106109d757604051806105708782610906565b600260206001926109e785612292565b8152019201920191906109c2565b3461036957604036600319011261036957600435602435610a406001600160a01b037f0000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe1633146122d8565b610a54826000526011602052604060002090565b91610a60835460ff1690565b835460ff19168455610a7181611726565b60018103610ab1575050610aac610aa6600161070e940192610a9b81610a968661233b565b6131b9565b600052602060002090565b9161233b565b613080565b80610abd600292611726565b03610ad25750610aac600161070e930161233b565b60405191825291507fc856f5dd60efc0d8ff81e7d44ad79d2f66c6e205f48321258f4c4fa9b40d879490602090a2005b6060906003190112610369576004356001600160a01b038116810361036957906024356001600160a01b0381168103610369579060443590565b346103695761070e610b4d36610b02565b91612386565b34610369576020366003190112610369576020610b71600435612530565b610b7e60405180926108c2565bf35b3461036957604036600319011261036957610b99610636565b6001600160a01b0360243591610bae8161298f565b831015610be45716600052600a602052604060002090600052602052610570604060002054604051918291829190602083019252565b63295f44f760e21b6000521660045260245260446000fd5b346103695760003660031901126103695760206040516001600160a01b037f0000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe168152f35b634e487b7160e01b600052600060045260246000fd5b90600182811c92168015610c86575b6020831014610c7057565b634e487b7160e01b600052602260045260246000fd5b91607f1691610c65565b60009291815491610ca083610c56565b8083529260018116908115610cf65750600114610cbc57505050565b60009081526020812093945091925b838310610cdc575060209250010190565b600181602092949394548385870101520191019190610ccb565b915050602093945060ff929192191683830152151560051b010190565b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff821117610d4557604052565b610d13565b6060810190811067ffffffffffffffff821117610d4557604052565b90601f8019910116810190811067ffffffffffffffff821117610d4557604052565b3461036957600036600319011261036957610570604051610db581610dae816000610c90565b0382610d66565b6040519182916020835260208301906104e1565b3461036957600036600319011261036957610de2612f7b565b47600080808084335af1610df4612584565b5015610e28576040519081527f0d844f1a03bee48636780fe86fa98a7dd80250e1739d2b598e5c1ae1c021b28d60203392a2005b606460405162461bcd60e51b815260206004820152601560248201527f446963653a207769746864726177206661696c656400000000000000000000006044820152fd5b346103695761070e610e7d36610b02565b9060405192610e8d602085610d66565b60008452610e9c838383612386565b613418565b34610369576000366003190112610369576020604051610b7e817f00000000000000000000000000000000000000000000000000000000000000016108c2565b3461036957602036600319011261036957600435600c54811015610f3257600c6000527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70154604051908152602090f35b63295f44f760e21b600052600060045260245260446000fd5b3461036957600036600319011261036957602060ff601354166040519015158152f35b60203660031901126103695760043567ffffffffffffffff8111610369573660238201121561036957806004013567ffffffffffffffff8111610369576024820191602436918360051b01011161036957610fd160ff60135460081c16156125b4565b610fe2610fdd826121bd565b6121f8565b6040805163085868e960e11b8152600481018390526001600160a01b037f0000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe169181602481855afa90811561086657600091611275575b50611045813410156125ff565b803411611215575b60005b84811061116e5750916020916110ac936110694261220a565b906040518096819582947f1f53cf040000000000000000000000000000000000000000000000000000000084526004840160209093929193604081019481520152565b03925af19081156108665760009161113f575b506110f86110cb6117c9565b600281526110da368587612766565b60208201526110f3836000526011602052604060002090565b6127c9565b60005b82811061110457005b808261111360019386886126b1565b357ffa76b3955fb2015dafb3312a1afed625a3705dfff7e20a905c803c16a058d801600080a3016110fb565b611161915060203d602011611167575b6111598183610d66565b810190612757565b386110bf565b503d61114f565b8061119e61119761118b6111856001958a8c6126b1565b35612fbd565b6001600160a01b031690565b33146122d8565b6111db60026111cc6111c56111b4858b8d6126b1565b35600052600f602052604060002090565b5460ff1690565b6111d581611726565b146126c1565b80156112105761120a6111ef82888a6126b1565b356112036111fc8461264a565b898b6126b1565b351061270c565b01611050565b61120a565b61123860008080806112278634612659565b335af1611232612584565b50612666565b6112428134612659565b60405190815233907f63e351cd0651c5ddd4bcc26ac590387707c971a4136303f334540176aaffa95390602090a261104d565b61128e915060403d60401161085f576108508183610d66565b5038611038565b34610369576020366003190112610369576105706112b46004356128a2565b6040519182916020835260208301906108cf565b346103695760203660031901126103695760206112e6600435612fbd565b6001600160a01b0360405191168152f35b3461036957600036600319011261036957604051600060015461131981610c56565b80845290600181169081156105d35750600114611340576105708361056481850382610d66565b600160009081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b80821061138557509091508101602001610564610554565b91926001816020925483858801015201910190929161136d565b3461036957600036600319011261036957602060405161c3508152f35b346103695760203660031901126103695760206113df6113da610636565b61298f565b604051908152f35b3461036957600036600319011261036957611400612f7b565b60006001600160a01b03600e5473ffffffffffffffffffffffffffffffffffffffff198116600e55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461036957602036600319011261036957610570610db561146e61088e565b612b05565b634e487b7160e01b600052603260045260246000fd5b80548210156114a15760005260206000200190600090565b611473565b346103695760403660031901126103695760043560243590600052601060205260406000208054821015610369576020916114e091611489565b90549060031b1c604051908152f35b34610369576000366003190112610369576020601254604051908152f35b346103695760003660031901126103695760206001600160a01b03600e5416604051908152f35b34610369576000366003190112610369576020604051620493e08152f35b3461036957600036600319011261036957604051600060055461157481610c56565b80845290600181169081156105d3575060011461159b576105708361056481850382610d66565b600560009081527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0939250905b8082106115e057509091508101602001610564610554565b9192600181602092548385880101520191019092916115c8565b346103695760003660031901126103695760206040517f000000000000000000000000000000000000000000000000000ef2273c1b08008152f35b346103695760403660031901126103695761164e610636565b6024358015158103610369576001600160a01b0382169182156116da57816116996116aa923360005260096020526040600020906001600160a01b0316600052602052604060002090565b9060ff801983541691151516179055565b60405190151581527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b827f5b08ba180000000000000000000000000000000000000000000000000000000060005260045260246000fd5b34610369576000366003190112610369576020604051620249f08152f35b600311156108bd57565b3461036957602036600319011261036957600435600052600f602052602060ff604060002054166040519061176481611726565b8152f35b3461036957600036600319011261036957602060ff60135460081c166040519015158152f35b346103695760003660031901126103695760206040517f00000000000000000000000000000000000000000000000000000000000000168152f35b604051906117d8604083610d66565b565b67ffffffffffffffff8111610d4557601f01601f191660200190565b929192611802826117da565b916118106040519384610d66565b829481845281830111610369578281602093846000960137010152565b3461036957608036600319011261036957611846610636565b61184e61064c565b906044356064359267ffffffffffffffff841161036957366023850112156103695761188761070e9436906024816004013591016117f6565b92610e9c838383612386565b34610369576000366003190112610369576118ac612f7b565b6012546118e357426012557f57fd5d9258bc5040104b1a0db17596ff674d188a2a5e45a80ad7c035c848adfb6020604051428152a1005b606460405162461bcd60e51b815260206004820152601a60248201527f446963653a206d696e7420616c726561647920737461727465640000000000006044820152fd5b346103695760203660031901126103695760043561194481612b71565b906000526010602052604060002090815491611961831515612513565b600019830192831161086b576119959261197a91611489565b90549060031b1c6040519283926040845260408401906104e1565b9060208301520390f35b346103695760203660031901126103695760043580620249f002620249f08104820361086b5760406107c76119d3926121f8565b03816001600160a01b037f0000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe165afa80156108665761057092611a4892600092611a58575b50611a43907f000000000000000000000000000000000000000000000000000ef2273c1b0800906121e5565b612226565b6040519081529081906020820190565b611a43919250611a769060403d60401161085f576108508183610d66565b509190611a17565b3461036957602036600319011261036957610570610db5600435612b71565b346103695760203660031901126103695760043560005260106020526020604060002054604051908152f35b346103695760203660031901126103695760043567ffffffffffffffff8111610369573660238201121561036957611b0b9036906024816004013591016117f6565b611b13612f7b565b805167ffffffffffffffff8111610d4557611b3881611b33600054610c56565b612e6c565b6020601f8211600114611bab5791611b8c82611b9b937f637f3fe47415bd9a869d5eec4d04a98a500a05fab915b6bea839c0d57831645795600091611ba0575b508160011b916000199060031b1c19161790565b60005560405191829182610506565b0390a1005b905083015138611b78565b60008052601f198216907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639160005b818110611c3a5750927f637f3fe47415bd9a869d5eec4d04a98a500a05fab915b6bea839c0d578316457949260019282611b9b9610611c21575b5050811b01600055610564565b84015160001960f88460031b161c191690553880611c14565b91926020600181928689015181550194019201611bda565b346103695760003660031901126103695760206040517f000000000000000000000000000000000000000000000000000000000002a3008152f35b9060208252602060808160608501938051611ca781611726565b8287015201519360408082015284518094520192019060005b818110611ccd5750505090565b8251845260209384019390920191600101611cc0565b346103695760203660031901126103695760043560606020604051611d0781610d29565b60008152015260005260116020526105706040600020611d45600160405192611d2f84610d29565b60ff815416611d3d81611726565b84520161233b565b602082015260405191829182611c8d565b3461036957604036600319011261036957602060ff611dac611d76610636565b6001600160a01b03611d8661064c565b9116600052600984526040600020906001600160a01b0316600052602052604060002090565b54166040519015158152f35b3461036957604036600319011261036957611dd161088e565b6024356001600160f01b038116810361036957611dec612865565b5060058210156108bd57611e136112b4916105709360005260026020526040600020612886565b50612292565b602036600319011261036957600435601254156120b457611e4260ff60135460081c16156125b4565b611e4a613923565b611e56610fdd826121d0565b6040805163085868e960e11b81526004810183905292916001600160a01b037f0000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe169184602481855afa93841561086657600094612092575b50611edd84611a437f000000000000000000000000000000000000000000000000000ef2273c1b0800866121e5565b91611eea833410156125ff565b823411612032575b611efd600c54612218565b94611f0785612f35565b9560005b868110611fe657505091602091611f25936110694261220a565b03925af190811561086657600091611fc7575b50611f62611f446117c9565b600181528560208201526110f3836000526011602052604060002090565b60005b838110611f6e57005b80611f85611f7e60019388612f67565b5133613a34565b611f8f8187612f67565b5160405185815233919085907f6a07643617236b9185b93ee3100548cc2f3d46f2188b50ef2f7b911158b1ba3e90602090a401611f65565b611fe0915060203d602011611167576111598183610d66565b38611f38565b80611ff360019284612226565b611ffd828b612f67565b5261202c61201f61200e838c612f67565b51600052600f602052604060002090565b805460ff19166001179055565b01611f0b565b61205560008080806120448834612659565b335af161204f612584565b50612eea565b61205f8334612659565b60405190815233907f63e351cd0651c5ddd4bcc26ac590387707c971a4136303f334540176aaffa95390602090a2611ef2565b6120ac91945060403d60401161085f576108508183610d66565b509238611eae565b606460405162461bcd60e51b815260206004820152601660248201527f446963653a206d696e74206e6f742073746172746564000000000000000000006044820152fd5b34610369576020366003190112610369576001600160a01b03612119610636565b612121612f7b565b168015612178576001600160a01b03600e548273ffffffffffffffffffffffffffffffffffffffff19821617600e55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b634e487b7160e01b600052601160045260246000fd5b908161c350029161c35083040361086b57565b9081620249f00291620249f083040361086b57565b8181029291811591840414171561086b57565b620493e0019081620493e01161086b57565b90601e820180921161086b57565b906001820180921161086b57565b9190820180921161086b57565b9190826040910312610369576020825192015190565b6040513d6000823e3d90fd5b60058110156108bd576000526002602052604060002090565b67ffffffffffffffff8111610d455760051b60200190565b60058210156108bd5752565b906001604080516122a281610d4a565b6122d4819580546122b660ff821685612286565b60081c60208401526122cd84518096819301610c90565b0384610d66565b0152565b156122df57565b606460405162461bcd60e51b815260206004820152601460248201527f446963653a20696e76616c69642073656e6465720000000000000000000000006044820152fd5b9061232d81611726565b60ff80198354169116179055565b906040519182815491828252602082019060005260206000209260005b81811061236d5750506117d892500383610d66565b8454835260019485019487945060209093019201612358565b9190916001600160a01b0383169081156124fd576001600160a01b03916000948486526006602052846123c4604088206001600160a01b0390541690565b92336124ed575b85841697881580156124ba575b6123f5856001600160a01b03166000526007602052604060002090565b60018154019055612414856106e6866000526006602052604060002090565b83838b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8580a4156124a45761244983613e6c565b508703612494575b5050501680830361246157505050565b7f64283d7b0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b61249d91613ece565b3884612451565b888214612449576124b58386613db2565b612449565b6124c384613b9c565b6124e0866001600160a01b03166000526007602052604060002090565b80546000190190556123d8565b6124f8823386613f60565b6123cb565b633250574960e11b600052600060045260246000fd5b1561251a57565b634e487b7160e01b600052600160045260246000fd5b61253e620f42408210612513565b6000906064811015612551575050600490565b6113ec811015612562575050600390565b62014c08811015612574575050600290565b620668a011156105175750600190565b3d156125af573d90612595826117da565b916125a36040519384610d66565b82523d6000602084013e565b606090565b156125bb57565b606460405162461bcd60e51b815260206004820152601860248201527f446963653a20636f6e74726163742069732070617573656400000000000000006044820152fd5b1561260657565b606460405162461bcd60e51b815260206004820152601a60248201527f446963653a20696e73756666696369656e74207061796d656e740000000000006044820152fd5b60001981019190821161086b57565b9190820391821161086b57565b1561266d57565b606460405162461bcd60e51b815260206004820152601360248201527f446963653a20726566756e64206661696c6564000000000000000000000000006044820152fd5b91908110156114a15760051b0190565b156126c857565b606460405162461bcd60e51b815260206004820152601860248201527f446963653a20746f6b656e206e6f742072657665616c656400000000000000006044820152fd5b1561271357565b606460405162461bcd60e51b815260206004820152601760248201527f446963653a20756e736f7274656420746f6b656e4964730000000000000000006044820152fd5b90816020910312610369575190565b9291906127728161226e565b936127806040519586610d66565b602085838152019160051b810192831161036957905b8282106127a257505050565b8135815260209182019101612796565b8181106127bd575050565b600081556001016127b2565b60016020916127e284516127dc81611726565b82612323565b019101519081519167ffffffffffffffff8311610d4557680100000000000000008311610d45576020908254848455808510612848575b500190600052602060002060005b8381106128345750505050565b600190602084519401938184015501612827565b61285f9084600052858460002091820191016127b2565b38612819565b6040519061287282610d4a565b606060408360008152600060208201520152565b80548210156114a15760005260206000209060011b0190600090565b6128aa612865565b5060005260036020526040600020604051906128c582610d4a565b549060ff82161515815260208101906128e460ff8460081c1683612286565b604081019260101c83525115612925576105179161291f612911611e13935161290c816108b3565b612255565b91516001600160f01b031690565b90612886565b608460405162461bcd60e51b815260206004820152602160248201527f446963653a20546f6b656e206d65746164617461206e6f742061737369676e6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b031680156129af57600052600760205260406000205490565b7f89c62b6400000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b604051906129ed604083610d66565b600982527f4c6567656e6461727900000000000000000000000000000000000000000000006020830152565b60405190612a28604083610d66565b600482527f45706963000000000000000000000000000000000000000000000000000000006020830152565b60405190612a63604083610d66565b600482527f52617265000000000000000000000000000000000000000000000000000000006020830152565b60405190612a9e604083610d66565b600882527f556e636f6d6d6f6e0000000000000000000000000000000000000000000000006020830152565b60405190612ad9604083610d66565b600682527f436f6d6d6f6e00000000000000000000000000000000000000000000000000006020830152565b612b0e816108b3565b80612b1c5750610517612aca565b612b25816108b3565b60018103612b365750610517612a8f565b612b3f816108b3565b60028103612b505750610517612a54565b80612b5c6003926108b3565b03612b6957610517612a19565b6105176129de565b612b7a81612fbd565b5080600052600f60205260406000205460ff16612b9681611726565b600214612ba2906126c1565b612bab816128a2565b90612bb581613f19565b91604051809360208201612bc8906134b4565b808251602081940191612bda926104be565b0103601f1981018452612bed9084610d66565b8051612bf8816108b3565b612c01816108b3565b612c0a90613f19565b906020810151612c20906001600160f81b031690565b6001600160f81b0316612c3290613f19565b91612c3d83826135c1565b92612c479161366b565b92612c5190613f19565b928151612c5d816108b3565b612c6690612b05565b91604001519260405195869560208701612ca4906016907f7b226e616d65223a224f6e636861696e2044696520230000000000000000000081520190565b612cad916135aa565b7f222c226465736372697074696f6e223a225265726f6c6c20796f75722064696381527f65207573696e672076657269666961626c652072616e646f6d6e657373206f6e60208201527f20646963652e616e7972616e642e636f6d222c2265787465726e616c5f75726c604082015262111d1160e91b6060820152606301612d34916135aa565b7f222c22696d616765223a220000000000000000000000000000000000000000008152600b01612d63916135aa565b7f222c22616e696d6174696f6e5f75726c223a22000000000000000000000000008152601301612d92916135aa565b7f222c2261747472696275746573223a205b7b2274726169745f74797065223a2281527f526172697479222c2276616c7565223a220000000000000000000000000000006020820152603101612de7916135aa565b7f227d2c207b2274726169745f74797065223a224d6f64656c222c2276616c7565815262111d1160e91b6020820152602301612e22916135aa565b7f227d5d7d00000000000000000000000000000000000000000000000000000000815260040103601f1981018252612e5a9082610d66565b612e639061405b565b61051790613716565b90601f8211612e79575050565b6117d891600080526020600020906020601f840160051c83019310612ea6575b601f0160051c01906127b2565b9091508190612e99565b9190601f8111612ebf57505050565b6117d8926000526020600020906020601f840160051c83019310612ea657601f0160051c01906127b2565b15612ef157565b606460405162461bcd60e51b815260206004820152601360248201527f446963653a20526566756e64206661696c6564000000000000000000000000006044820152fd5b90612f3f8261226e565b612f4c6040519182610d66565b8281528092612f5d601f199161226e565b0190602036910137565b80518210156114a15760209160051b010190565b6001600160a01b03600e54163303612f8f57565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b8060005260066020526001600160a01b0360406000205416908115612fe0575090565b637e27328960e01b60005260045260246000fd5b15612ffb57565b606460405162461bcd60e51b815260206004820152601960248201527f446963653a20696e76616c696420746f6b656e207374617465000000000000006044820152fd5b9081549168010000000000000000831015610d4557826130679160016117d895018155611489565b90919082549060031b91821b91600019901b1916179055565b919060005b835181101561317e578061309b60019286612f67565b516130c8600260ff6130b784600052600f602052604060002090565b54166130c281611726565b14612ff4565b7f55a80d8c44b8f38d921a310dd9d3f9966452d3468ef1ebfb93adae63ce5bcd3861312e61312960405161311f816131118a886020840160209093929193604081019481520152565b03601f198101835282610d66565b6020815191012090565b613bed565b61314b81613146856000526010602052604060002090565b61303f565b613168613162846000526010602052604060002090565b5461264a565b604080519182526020820192909252a201613085565b50509050565b9060016080610517936020815283546131a36020830160ff83166108c2565b60081c6040820152606080820152019101610c90565b919060005b835181101561317e57806131d460019286612f67565b516131f9836131f06111c584600052600f602052604060002090565b6130c281611726565b61321d61321082600052600f602052604060002090565b805460ff19166002179055565b7f6c9cd8284a3a8f9758cddfea0e2b2fa713d646f3ea6a14cc11896a821499bda96132bb6132ae61326960405161311f816131118b896020840160209093929193604081019481520152565b61327a61327582613c1b565b612530565b9061328482612255565b805490918982036132c45750506132a96000925b6001600160f01b0384169088613ce2565b612886565b5060405191829182613184565b0390a2016131be565b6132a9916132da6132df92600052602060002090565b613c4c565b92613298565b90816020910312610369575161051781610357565b90926001600160a01b03608093816105179796168452166020830152604082015281606082015201906104e1565b9190823b61333557505050565b61335a916020916040519384928392630a85bd0160e11b8452600033600486016132fa565b038160006001600160a01b0387165af1600091816133e7575b506133af5750613381612584565b80519190826133a857633250574960e11b6000526001600160a01b03821660045260246000fd5b9050602001fd5b6001600160e01b0319630a85bd0160e11b9116036133ca5750565b633250574960e11b6000526001600160a01b031660045260246000fd5b61340a91925060203d602011613411575b6134028183610d66565b8101906132e5565b9038613373565b503d6133f8565b909291833b613428575b50505050565b60209161344a6040519485938493630a85bd0160e11b855233600486016132fa565b038160006001600160a01b0387165af160009181613493575b506134715750613381612584565b6001600160e01b0319630a85bd0160e11b9116036133ca575038808080613422565b6134ad91925060203d602011613411576134028183610d66565b9038613463565b90600091600054906134c582610c56565b916001811690811561352a57506001146134dd575050565b600080805292935090917f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8382106135165750500190565b600181602092548486015201910190613509565b60ff1916825250811515909102019150565b6000929181549161354c83610c56565b9260018116908115613597575060011461356557505050565b909192935060005260206000206000905b8382106135835750500190565b600181602092548486015201910190613576565b60ff191683525050811515909102019150565b906135bd602092828151948592016104be565b0190565b600460016117d892949394826040519687926135e0602085018661353c565b7f696d672f00000000000000000000000000000000000000000000000000000000815261361682518093602087850191016104be565b01602f60f81b838201526136348251809360206005850191016104be565b01017f2e706e6700000000000000000000000000000000000000000000000000000000838201520301601b19810185520183610d66565b600460016117d892949394600560405196879261368b602085018661353c565b7f676c74662f00000000000000000000000000000000000000000000000000000081526136c182518093602087850191016104be565b01602f60f81b838201526136df8251809360206006850191016104be565b01017f2e676c6200000000000000000000000000000000000000000000000000000000838201520301601b19810185520183610d66565b906117d8603d60405180947f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000602083015261375a81518092602086860191016104be565b81010301601f198101845283610d66565b9092919261386e57825160058110156108bd57602084015160081b60ff191660ff90911617815560409290920151805190926001019067ffffffffffffffff8111610d45576137c4816137be8454610c56565b84612eb0565b6020601f82116001146138055781906137f69394956000926137fa575b50508160011b916000199060031b1c19161790565b9055565b0151905038806137e1565b601f1982169061381a84600052602060002090565b9160005b8181106138565750958360019596971061383d575b505050811b019055565b015160001960f88460031b161c19169055388080613833565b9192602060018192868b01518155019401920161381e565b610c40565b805480156138f857600019019061388a8282612886565b61386e5780600060019255016138a08154610c56565b90816138ab57505055565b601f82116001146138bf5760009055505b55565b6138e76138bc926001601f6138d985600052602060002090565b920160051c820191016127b2565b600081815260208120918190559055565b634e487b7160e01b600052603160045260246000fd5b602090939291936122d48160408101966108c2565b60135460ff16156117d85761395b6012547f000000000000000000000000000000000000000000000000000000000002a30090612226565b42106117d8577fd1dc84168a0cf4a73527c9d58ff29ec6e1e0691a0dbc44df352750933052a17d7f00000000000000000000000000000000000000000000000000000000000000016139ac81612255565b90613a116139c6611e136139c0855461264a565b85612886565b7f00000000000000000000000000000000000000000000000000000000000000166001600160f81b03811660208301529390613a0c90613a068684612886565b9061376b565b613873565b613a2060ff1960135416601355565b613a2f6040519283928361390e565b0390a1565b9060405190613a44602083610d66565b600082526001600160a01b03831680156124fd576000908282526006602052613a78604083206001600160a01b0390541690565b906001600160a01b03821680159384159485613b69575b613aac896001600160a01b03166000526007602052604060002090565b60018154019055613acb896106e6896000526006602052604060002090565b8684847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8580a415613b5357613b0086613e6c565b5003613b44575b50613b15576117d892613328565b7f73c6ac6e00000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b613b4e8386613ece565b613b07565b818314613b0057613b648685613db2565b613b00565b613b7287613b9c565b613b8f856001600160a01b03166000526007602052604060002090565b8054600019019055613a8f565b613bb0906000526008602052604060002090565b805473ffffffffffffffffffffffffffffffffffffffff19169055565b8115613bd7570690565b634e487b7160e01b600052601260045260246000fd5b600060015b15613c08575b5060008181526020812090613bf2565b600319811015613bf85790506006900690565b600060015b15613c36575b5060008181526020812090613c20565b6209c3bf19811015613c2657620f424091500690565b908015613bd757806000190619600060015b15613c74575b5060008381526020812090613c5e565b81811015613c645790506105179250613bcd565b90613ca281511515839060ff801983541691151516179055565b602081015160058110156108bd57613ccc61ffff9184549061ff009060081b169061ff0019161790565b918284556040821991015160101b169116179055565b9182600052600360205260ff60406000205416613d48576117d892613d33613d4392613d2360405195613d16606088610d66565b6001875260208701612286565b6001600160f01b03166040850152565b6000526003602052604060002090565b613c88565b608460405162461bcd60e51b815260206004820152602560248201527f446963653a20546f6b656e206d6574616461746120616c72656164792061737360448201527f69676e65640000000000000000000000000000000000000000000000000000006064820152fd5b600091613e0a6138bc9284613df0613dc98361298f565b94808352600b6020526040832054868103613e19575b50600052600b602052604060002090565b556001600160a01b0316600052600a602052604060002090565b90600052602052604060002090565b613e656001600160a01b038616808652600a602052604086208987526020526040862054908652600a60205260408620838752602052806040872055600052600b602052604060002090565b5538613ddf565b600c5481600052600d602052604060002055600c5468010000000000000000811015610d455760018101600c556000600c548210156114a157600c90527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70155565b90613ed88261298f565b60001981019290831161086b576001600160a01b0316600052600a60205260406000208260005260205280604060002055600052600b602052604060002055565b90604051600a608082019360a0830160405260008552935b6000190193603082820601855304928315613f4e57600a90613f31565b809350608091030191601f1901918252565b919091613f7e6001600160a01b0384168015159081613fe357501590565b613f8757505050565b6001600160a01b0316613fa857637e27328960e01b60005260045260246000fd5b7f177e802f000000000000000000000000000000000000000000000000000000006000526001600160a01b0390911660045260245260446000fd5b6001600160a01b03841680821492508215614024575b50811561400557501590565b90508360005260086020526001600160a01b0360406000205416141590565b909150600052600960205260ff614052866040600020906001600160a01b0316600052602052604060002090565b54169038613ff9565b8051606092918161406a575050565b9092506003600284010460021b90604051937f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106707f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f5260208501918386019060208201926020818301019460046003875194600089525b0191603f8351818160121c16516000538181600c1c1651600153818160061c16516002531651600353600051815201908582101561412c576004906003906140e9565b50935060407f3d3d0000000000000000000000000000000000000000000000000000000000009360039360009752016040520660020482035252825256fea2646970667358221220ec0f9fe603f47c29f7103b48e5135e04137d46cb324dbe1fa698ec8b558cd8b964736f6c634300081a0033

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

000000000000000000000000000000000000000000000000000ef2273c1b08000000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000000036697066733a2f2f516d57506944673134596350374e7241736e384b5575734b464169454e795031784752367546647156714e4e6e6d2f00000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000fc00000000000000000000000000000000000000000000000000000000000001b2000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000026c0000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000740000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000008c000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000000000000000000000000098000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000b400000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000bc00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000cc00000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000d800000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000e400000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000ec0000000000000000000000000000000000000000000000000000000000000000f416c756d696e69756d20426c61636b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e416c756d696e69756d20426c7565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f416c756d696e69756d20477265656e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014416c756d696e69756d204c6967687420426c75650000000000000000000000000000000000000000000000000000000000000000000000000000000000000010416c756d696e69756d204f72616e6765000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010416c756d696e69756d20507572706c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d416c756d696e69756d20526564000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010416c756d696e69756d2053696c766572000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010416c756d696e69756d2059656c6c6f7700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b436173696e6f20426c7565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c436173696e6f20477265656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d436173696e6f20507572706c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a436173696e6f2052656400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d436173696e6f2059656c6c6f7700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e477261666669746920426c61636b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d477261666669746920426c756500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e477261666669746920477265656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4772616666697469204f72616e67650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d47726166666974692050696e6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010477261666669746920507572706c652000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c4772616666697469205265640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4772616666697469205768697465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4a75737420426c61636b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000094a75737420426c75650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4a75737420477265656e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4a757374204f72616e676500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000094a7573742050696e6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4a75737420507572706c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084a75737420526564000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4a75737420576869746500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4a7573742059656c6c6f77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b506978656c20426c61636b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a506978656c20426c756500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b506978656c20477265656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c506978656c204f72616e67650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b506978656c2050696e6b20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c506978656c20507572706c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009506978656c205265640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c506978656c205768697465200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d506978656c2059656c6c6f772000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000740000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000008c000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000000000000000000000000098000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000007416e7972616e64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007426974636f696e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005436c75627300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000094461726b20576f6f64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084469616d6f6e64730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008457468657265756d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006486561727473000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4b616e6a6920426c756500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4b616e6a6920477265656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4b616e6a692050696e6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c4b616e6a692059656c6c6f77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044b6977690000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000114c6561677565206f6620456e74726f707900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000094d617a6520426c75650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4d617a6520477265656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d617a6520526564000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4d617a652059656c6c6f7700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064f72616e6765000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044f74746f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000752616e64616d7500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b526f6d616e2053746f6e6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065363726f6c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065370616465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001454686520436972636c652047616d6520426c7565000000000000000000000000000000000000000000000000000000000000000000000000000000000000001554686520436972636c652047616d6520477265656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000001354686520436972636c652047616d652052656400000000000000000000000000000000000000000000000000000000000000000000000000000000000000001654686520436972636c652047616d652059656c6c6f7700000000000000000000000000000000000000000000000000000000000000000000000000000000000a57617465726d656c6f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004576f6f64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006c00000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000074000000000000000000000000000000000000000000000000000000000000000064172726f77730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642696e61727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005427261696e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642726f6e7a650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4469636553746174696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007466c6f77657273000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008466f6f7462616c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000547686f7374000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c476f6c64656e20436c7562730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f476f6c64656e204469616d6f6e64730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d476f6c64656e2048656172747300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d476f6c64656e205370616465730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044c65676f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054e617a6172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000550617274790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009506f77657242616c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a52617265205761677975000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012526f6d616e205768697465204d6172626c650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5469632d7461632d746f65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000859696e6759616e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000005436c6f636b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001049276d207761746368696e6720796f750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074f442d30363958000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012526f6d616e20426c61636b204d6172626c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005527562696b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000653696c7665720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000753796e6368726f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e5468652045706963204368656573652043756265206f6620457465726e616c6c79204167656420466f7274756e6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000075472617070656400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b576861632d412d4d6f6c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e54686520476f6c64656e20446965000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : price_ (uint256): 4206900000000000
Arg [1] : randomiser_ (address): 0x7ED45287f817842d72753FE02617629c4c7c2FBE
Arg [2] : baseURI_ (string): ipfs://QmWPiDg14YcP7NrAsn8KUusKFAiENyP1xGR6uFdqVqNNnm/
Arg [3] : tokenModels_ (string[][]): System.Collections.Generic.List`1[System.String],System.Collections.Generic.List`1[System.String],System.Collections.Generic.List`1[System.String],System.Collections.Generic.List`1[System.String],System.Collections.Generic.List`1[System.String]
Arg [4] : leModelRarity_ (uint8): 1
Arg [5] : leModelIdx_ (uint256): 22
Arg [6] : leModelPeriod_ (uint256): 172800

-----Encoded View---------------
325 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000000000000000000000ef2273c1b0800
Arg [1] : 0000000000000000000000007ed45287f817842d72753fe02617629c4c7c2fbe
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [6] : 000000000000000000000000000000000000000000000000000000000002a300
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000036
Arg [8] : 697066733a2f2f516d57506944673134596350374e7241736e384b5575734b46
Arg [9] : 4169454e795031784752367546647156714e4e6e6d2f00000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [11] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000fc0
Arg [13] : 0000000000000000000000000000000000000000000000000000000000001b20
Arg [14] : 00000000000000000000000000000000000000000000000000000000000022c0
Arg [15] : 00000000000000000000000000000000000000000000000000000000000026c0
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000028
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000500
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000540
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000580
Arg [20] : 00000000000000000000000000000000000000000000000000000000000005c0
Arg [21] : 0000000000000000000000000000000000000000000000000000000000000600
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000640
Arg [23] : 0000000000000000000000000000000000000000000000000000000000000680
Arg [24] : 00000000000000000000000000000000000000000000000000000000000006c0
Arg [25] : 0000000000000000000000000000000000000000000000000000000000000700
Arg [26] : 0000000000000000000000000000000000000000000000000000000000000740
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000780
Arg [28] : 00000000000000000000000000000000000000000000000000000000000007c0
Arg [29] : 0000000000000000000000000000000000000000000000000000000000000800
Arg [30] : 0000000000000000000000000000000000000000000000000000000000000840
Arg [31] : 0000000000000000000000000000000000000000000000000000000000000880
Arg [32] : 00000000000000000000000000000000000000000000000000000000000008c0
Arg [33] : 0000000000000000000000000000000000000000000000000000000000000900
Arg [34] : 0000000000000000000000000000000000000000000000000000000000000940
Arg [35] : 0000000000000000000000000000000000000000000000000000000000000980
Arg [36] : 00000000000000000000000000000000000000000000000000000000000009c0
Arg [37] : 0000000000000000000000000000000000000000000000000000000000000a00
Arg [38] : 0000000000000000000000000000000000000000000000000000000000000a40
Arg [39] : 0000000000000000000000000000000000000000000000000000000000000a80
Arg [40] : 0000000000000000000000000000000000000000000000000000000000000ac0
Arg [41] : 0000000000000000000000000000000000000000000000000000000000000b00
Arg [42] : 0000000000000000000000000000000000000000000000000000000000000b40
Arg [43] : 0000000000000000000000000000000000000000000000000000000000000b80
Arg [44] : 0000000000000000000000000000000000000000000000000000000000000bc0
Arg [45] : 0000000000000000000000000000000000000000000000000000000000000c00
Arg [46] : 0000000000000000000000000000000000000000000000000000000000000c40
Arg [47] : 0000000000000000000000000000000000000000000000000000000000000c80
Arg [48] : 0000000000000000000000000000000000000000000000000000000000000cc0
Arg [49] : 0000000000000000000000000000000000000000000000000000000000000d00
Arg [50] : 0000000000000000000000000000000000000000000000000000000000000d40
Arg [51] : 0000000000000000000000000000000000000000000000000000000000000d80
Arg [52] : 0000000000000000000000000000000000000000000000000000000000000dc0
Arg [53] : 0000000000000000000000000000000000000000000000000000000000000e00
Arg [54] : 0000000000000000000000000000000000000000000000000000000000000e40
Arg [55] : 0000000000000000000000000000000000000000000000000000000000000e80
Arg [56] : 0000000000000000000000000000000000000000000000000000000000000ec0
Arg [57] : 000000000000000000000000000000000000000000000000000000000000000f
Arg [58] : 416c756d696e69756d20426c61636b0000000000000000000000000000000000
Arg [59] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [60] : 416c756d696e69756d20426c7565000000000000000000000000000000000000
Arg [61] : 000000000000000000000000000000000000000000000000000000000000000f
Arg [62] : 416c756d696e69756d20477265656e0000000000000000000000000000000000
Arg [63] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [64] : 416c756d696e69756d204c6967687420426c7565000000000000000000000000
Arg [65] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [66] : 416c756d696e69756d204f72616e676500000000000000000000000000000000
Arg [67] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [68] : 416c756d696e69756d20507572706c6500000000000000000000000000000000
Arg [69] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [70] : 416c756d696e69756d2052656400000000000000000000000000000000000000
Arg [71] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [72] : 416c756d696e69756d2053696c76657200000000000000000000000000000000
Arg [73] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [74] : 416c756d696e69756d2059656c6c6f7700000000000000000000000000000000
Arg [75] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [76] : 436173696e6f20426c7565000000000000000000000000000000000000000000
Arg [77] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [78] : 436173696e6f20477265656e0000000000000000000000000000000000000000
Arg [79] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [80] : 436173696e6f20507572706c6500000000000000000000000000000000000000
Arg [81] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [82] : 436173696e6f2052656400000000000000000000000000000000000000000000
Arg [83] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [84] : 436173696e6f2059656c6c6f7700000000000000000000000000000000000000
Arg [85] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [86] : 477261666669746920426c61636b000000000000000000000000000000000000
Arg [87] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [88] : 477261666669746920426c756500000000000000000000000000000000000000
Arg [89] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [90] : 477261666669746920477265656e000000000000000000000000000000000000
Arg [91] : 000000000000000000000000000000000000000000000000000000000000000f
Arg [92] : 4772616666697469204f72616e67650000000000000000000000000000000000
Arg [93] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [94] : 47726166666974692050696e6b00000000000000000000000000000000000000
Arg [95] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [96] : 477261666669746920507572706c652000000000000000000000000000000000
Arg [97] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [98] : 4772616666697469205265640000000000000000000000000000000000000000
Arg [99] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [100] : 4772616666697469205768697465000000000000000000000000000000000000
Arg [101] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [102] : 4a75737420426c61636b00000000000000000000000000000000000000000000
Arg [103] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [104] : 4a75737420426c75650000000000000000000000000000000000000000000000
Arg [105] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [106] : 4a75737420477265656e00000000000000000000000000000000000000000000
Arg [107] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [108] : 4a757374204f72616e6765000000000000000000000000000000000000000000
Arg [109] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [110] : 4a7573742050696e6b0000000000000000000000000000000000000000000000
Arg [111] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [112] : 4a75737420507572706c65000000000000000000000000000000000000000000
Arg [113] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [114] : 4a75737420526564000000000000000000000000000000000000000000000000
Arg [115] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [116] : 4a75737420576869746500000000000000000000000000000000000000000000
Arg [117] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [118] : 4a7573742059656c6c6f77000000000000000000000000000000000000000000
Arg [119] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [120] : 506978656c20426c61636b000000000000000000000000000000000000000000
Arg [121] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [122] : 506978656c20426c756500000000000000000000000000000000000000000000
Arg [123] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [124] : 506978656c20477265656e000000000000000000000000000000000000000000
Arg [125] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [126] : 506978656c204f72616e67650000000000000000000000000000000000000000
Arg [127] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [128] : 506978656c2050696e6b20000000000000000000000000000000000000000000
Arg [129] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [130] : 506978656c20507572706c650000000000000000000000000000000000000000
Arg [131] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [132] : 506978656c205265640000000000000000000000000000000000000000000000
Arg [133] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [134] : 506978656c205768697465200000000000000000000000000000000000000000
Arg [135] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [136] : 506978656c2059656c6c6f772000000000000000000000000000000000000000
Arg [137] : 000000000000000000000000000000000000000000000000000000000000001e
Arg [138] : 00000000000000000000000000000000000000000000000000000000000003c0
Arg [139] : 0000000000000000000000000000000000000000000000000000000000000400
Arg [140] : 0000000000000000000000000000000000000000000000000000000000000440
Arg [141] : 0000000000000000000000000000000000000000000000000000000000000480
Arg [142] : 00000000000000000000000000000000000000000000000000000000000004c0
Arg [143] : 0000000000000000000000000000000000000000000000000000000000000500
Arg [144] : 0000000000000000000000000000000000000000000000000000000000000540
Arg [145] : 0000000000000000000000000000000000000000000000000000000000000580
Arg [146] : 00000000000000000000000000000000000000000000000000000000000005c0
Arg [147] : 0000000000000000000000000000000000000000000000000000000000000600
Arg [148] : 0000000000000000000000000000000000000000000000000000000000000640
Arg [149] : 0000000000000000000000000000000000000000000000000000000000000680
Arg [150] : 00000000000000000000000000000000000000000000000000000000000006c0
Arg [151] : 0000000000000000000000000000000000000000000000000000000000000700
Arg [152] : 0000000000000000000000000000000000000000000000000000000000000740
Arg [153] : 0000000000000000000000000000000000000000000000000000000000000780
Arg [154] : 00000000000000000000000000000000000000000000000000000000000007c0
Arg [155] : 0000000000000000000000000000000000000000000000000000000000000800
Arg [156] : 0000000000000000000000000000000000000000000000000000000000000840
Arg [157] : 0000000000000000000000000000000000000000000000000000000000000880
Arg [158] : 00000000000000000000000000000000000000000000000000000000000008c0
Arg [159] : 0000000000000000000000000000000000000000000000000000000000000900
Arg [160] : 0000000000000000000000000000000000000000000000000000000000000940
Arg [161] : 0000000000000000000000000000000000000000000000000000000000000980
Arg [162] : 00000000000000000000000000000000000000000000000000000000000009c0
Arg [163] : 0000000000000000000000000000000000000000000000000000000000000a00
Arg [164] : 0000000000000000000000000000000000000000000000000000000000000a40
Arg [165] : 0000000000000000000000000000000000000000000000000000000000000a80
Arg [166] : 0000000000000000000000000000000000000000000000000000000000000ac0
Arg [167] : 0000000000000000000000000000000000000000000000000000000000000b00
Arg [168] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [169] : 416e7972616e6400000000000000000000000000000000000000000000000000
Arg [170] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [171] : 426974636f696e00000000000000000000000000000000000000000000000000
Arg [172] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [173] : 436c756273000000000000000000000000000000000000000000000000000000
Arg [174] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [175] : 4461726b20576f6f640000000000000000000000000000000000000000000000
Arg [176] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [177] : 4469616d6f6e6473000000000000000000000000000000000000000000000000
Arg [178] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [179] : 457468657265756d000000000000000000000000000000000000000000000000
Arg [180] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [181] : 4865617274730000000000000000000000000000000000000000000000000000
Arg [182] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [183] : 4963650000000000000000000000000000000000000000000000000000000000
Arg [184] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [185] : 4b616e6a6920426c756500000000000000000000000000000000000000000000
Arg [186] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [187] : 4b616e6a6920477265656e000000000000000000000000000000000000000000
Arg [188] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [189] : 4b616e6a692050696e6b00000000000000000000000000000000000000000000
Arg [190] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [191] : 4b616e6a692059656c6c6f770000000000000000000000000000000000000000
Arg [192] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [193] : 4b69776900000000000000000000000000000000000000000000000000000000
Arg [194] : 0000000000000000000000000000000000000000000000000000000000000011
Arg [195] : 4c6561677565206f6620456e74726f7079000000000000000000000000000000
Arg [196] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [197] : 4d617a6520426c75650000000000000000000000000000000000000000000000
Arg [198] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [199] : 4d617a6520477265656e00000000000000000000000000000000000000000000
Arg [200] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [201] : 4d617a6520526564000000000000000000000000000000000000000000000000
Arg [202] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [203] : 4d617a652059656c6c6f77000000000000000000000000000000000000000000
Arg [204] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [205] : 4f72616e67650000000000000000000000000000000000000000000000000000
Arg [206] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [207] : 4f74746f00000000000000000000000000000000000000000000000000000000
Arg [208] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [209] : 52616e64616d7500000000000000000000000000000000000000000000000000
Arg [210] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [211] : 526f6d616e2053746f6e65000000000000000000000000000000000000000000
Arg [212] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [213] : 5363726f6c6c0000000000000000000000000000000000000000000000000000
Arg [214] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [215] : 5370616465730000000000000000000000000000000000000000000000000000
Arg [216] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [217] : 54686520436972636c652047616d6520426c7565000000000000000000000000
Arg [218] : 0000000000000000000000000000000000000000000000000000000000000015
Arg [219] : 54686520436972636c652047616d6520477265656e0000000000000000000000
Arg [220] : 0000000000000000000000000000000000000000000000000000000000000013
Arg [221] : 54686520436972636c652047616d652052656400000000000000000000000000
Arg [222] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [223] : 54686520436972636c652047616d652059656c6c6f7700000000000000000000
Arg [224] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [225] : 57617465726d656c6f6e00000000000000000000000000000000000000000000
Arg [226] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [227] : 576f6f6400000000000000000000000000000000000000000000000000000000
Arg [228] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [229] : 0000000000000000000000000000000000000000000000000000000000000280
Arg [230] : 00000000000000000000000000000000000000000000000000000000000002c0
Arg [231] : 0000000000000000000000000000000000000000000000000000000000000300
Arg [232] : 0000000000000000000000000000000000000000000000000000000000000340
Arg [233] : 0000000000000000000000000000000000000000000000000000000000000380
Arg [234] : 00000000000000000000000000000000000000000000000000000000000003c0
Arg [235] : 0000000000000000000000000000000000000000000000000000000000000400
Arg [236] : 0000000000000000000000000000000000000000000000000000000000000440
Arg [237] : 0000000000000000000000000000000000000000000000000000000000000480
Arg [238] : 00000000000000000000000000000000000000000000000000000000000004c0
Arg [239] : 0000000000000000000000000000000000000000000000000000000000000500
Arg [240] : 0000000000000000000000000000000000000000000000000000000000000540
Arg [241] : 0000000000000000000000000000000000000000000000000000000000000580
Arg [242] : 00000000000000000000000000000000000000000000000000000000000005c0
Arg [243] : 0000000000000000000000000000000000000000000000000000000000000600
Arg [244] : 0000000000000000000000000000000000000000000000000000000000000640
Arg [245] : 0000000000000000000000000000000000000000000000000000000000000680
Arg [246] : 00000000000000000000000000000000000000000000000000000000000006c0
Arg [247] : 0000000000000000000000000000000000000000000000000000000000000700
Arg [248] : 0000000000000000000000000000000000000000000000000000000000000740
Arg [249] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [250] : 4172726f77730000000000000000000000000000000000000000000000000000
Arg [251] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [252] : 42696e6172790000000000000000000000000000000000000000000000000000
Arg [253] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [254] : 427261696e000000000000000000000000000000000000000000000000000000
Arg [255] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [256] : 42726f6e7a650000000000000000000000000000000000000000000000000000
Arg [257] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [258] : 4469636553746174696f6e000000000000000000000000000000000000000000
Arg [259] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [260] : 466c6f7765727300000000000000000000000000000000000000000000000000
Arg [261] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [262] : 466f6f7462616c6c000000000000000000000000000000000000000000000000
Arg [263] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [264] : 47686f7374000000000000000000000000000000000000000000000000000000
Arg [265] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [266] : 476f6c64656e20436c7562730000000000000000000000000000000000000000
Arg [267] : 000000000000000000000000000000000000000000000000000000000000000f
Arg [268] : 476f6c64656e204469616d6f6e64730000000000000000000000000000000000
Arg [269] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [270] : 476f6c64656e2048656172747300000000000000000000000000000000000000
Arg [271] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [272] : 476f6c64656e2053706164657300000000000000000000000000000000000000
Arg [273] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [274] : 4c65676f00000000000000000000000000000000000000000000000000000000
Arg [275] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [276] : 4e617a6172000000000000000000000000000000000000000000000000000000
Arg [277] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [278] : 5061727479000000000000000000000000000000000000000000000000000000
Arg [279] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [280] : 506f77657242616c640000000000000000000000000000000000000000000000
Arg [281] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [282] : 5261726520576167797500000000000000000000000000000000000000000000
Arg [283] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [284] : 526f6d616e205768697465204d6172626c650000000000000000000000000000
Arg [285] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [286] : 5469632d7461632d746f65000000000000000000000000000000000000000000
Arg [287] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [288] : 59696e6759616e67000000000000000000000000000000000000000000000000
Arg [289] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [290] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [291] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [292] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [293] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [294] : 0000000000000000000000000000000000000000000000000000000000000240
Arg [295] : 0000000000000000000000000000000000000000000000000000000000000280
Arg [296] : 00000000000000000000000000000000000000000000000000000000000002c0
Arg [297] : 0000000000000000000000000000000000000000000000000000000000000300
Arg [298] : 0000000000000000000000000000000000000000000000000000000000000360
Arg [299] : 00000000000000000000000000000000000000000000000000000000000003a0
Arg [300] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [301] : 436c6f636b000000000000000000000000000000000000000000000000000000
Arg [302] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [303] : 49276d207761746368696e6720796f7500000000000000000000000000000000
Arg [304] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [305] : 4f442d3036395800000000000000000000000000000000000000000000000000
Arg [306] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [307] : 526f6d616e20426c61636b204d6172626c650000000000000000000000000000
Arg [308] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [309] : 527562696b000000000000000000000000000000000000000000000000000000
Arg [310] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [311] : 53696c7665720000000000000000000000000000000000000000000000000000
Arg [312] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [313] : 53796e6368726f00000000000000000000000000000000000000000000000000
Arg [314] : 000000000000000000000000000000000000000000000000000000000000002e
Arg [315] : 5468652045706963204368656573652043756265206f6620457465726e616c6c
Arg [316] : 79204167656420466f7274756e65000000000000000000000000000000000000
Arg [317] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [318] : 5472617070656400000000000000000000000000000000000000000000000000
Arg [319] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [320] : 576861632d412d4d6f6c65000000000000000000000000000000000000000000
Arg [321] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [322] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [323] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [324] : 54686520476f6c64656e20446965000000000000000000000000000000000000


Block Transaction Gas Used Reward
view all blocks sequenced

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

Validator Index Block Amount
View All Withdrawals

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

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