ETH Price: $3,836.93 (+6.06%)

Token

ERC-20: UndeadChef (UNDEADCHEFS)
 

Overview

Max Total Supply

4,000 UNDEADCHEFS

Holders

775

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
2 UNDEADCHEFS
0xb17074852b0eD6dB294eF394a2e350b35b3D70d4
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
UndeadChef

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 14 : UndeadChef.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

// Contract by @AsteriaLabs
import "./Reg_ERC721Batch.sol";
import "./utils/ERC173.sol";
import "./interfaces/DefaultOperatorFilterer.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

/// @title Undead Chef
/// @author <@Suleman132446>
contract UndeadChef is
    Reg_ERC721Batch,
    ERC173,
    DefaultOperatorFilterer
{
    using MerkleProof for bytes32[];

    uint256 public whitelistPrice = 0.005 ether;
    uint256 public publicPrice = 0.005 ether;
    uint256 public maxPerWhitelist = 3;
    uint256 public maxPerPublic = 3;
    uint256 public maxSupply = 4000;

    
    error Whitelist_NOT_SET();
    error Whitelist_CONSUMED(address account);
    error Whitelist_FORBIDDEN(address account);

    bytes32 private _root;
    mapping(address => bool) private _private_consumed;
    mapping(address => bool) private _private_next;

    /**
     @dev An enum representing the sale state
     */
    enum Sale {
        PAUSED,
        PRIVATE,
        PRIVATE_NEXT,
        PUBLIC
    }

    Sale public saleState = Sale.PAUSED;
    // Mapping of nft minted by a wallet in public
    mapping(address => uint256) public mintedPerWallet;

    // Modifier to allow only owner

    // Modifier to check the sale state
    modifier isSaleState(Sale sale_) {
        require(saleState == sale_, "Sale not active");
        _;
    }

    // Modifier to block the other contracts
    modifier blockContracts() {
        require(tx.origin == msg.sender, "No smart contracts are allowed");
        _;
    }

    constructor(
        string memory name_,
        string memory symbol_,
        string memory baseURI_
    ) {
        __init_ERC721Metadata(name_, symbol_, baseURI_);
        _setOwner(msg.sender);
    }

    /**
     * @dev tranfer the funds from contract
     *
     * @param to_ : the address of the wallet to transfer the funds
     */
    function withdraw(address to_, uint amount_) public onlyOwner {
        uint256 _balance_ = address(this).balance;
        require(_balance_ > 0, "No balance to withdraw");
        require(amount_ <= _balance_, "Amount is not valid");
        address _recipient_ = payable(to_);
        (bool _success_, ) = _recipient_.call{value: amount_}("");
        require(_success_, "Transaction failed");
    }

    /**
     * @dev set the whiltelist price
     *
     * @param price_ : the price of whitelist mint
     */
    function setWhitelistPrice(uint256 price_) external onlyOwner {
        whitelistPrice = price_;
    }

    /**
     * @dev set the public mint price
     *
     * @param price_ : the price of public mint
     */
    function setPublicPrice(uint256 price_) external onlyOwner {
        publicPrice = price_;
    }

    /**
     * @dev set the mints per wallet in whitelist
     *
     * @param mints_ : the amount of for whitelist mint
     */
    function setMintsPerWhitelist(uint256 mints_) external onlyOwner {
        maxPerWhitelist = mints_;
    }

    /**
     * @dev set the mints per wallet in public
     *
     * @param mints_ : the amount of for public mint
     */
    function setMintsPerPublic(uint256 mints_) external onlyOwner {
        maxPerPublic = mints_;
    }

    /**
     * @dev set the max supply for collection
     *
     * @param supply_ : the amount for  supply
     */
    function setMaxSupply(uint256 supply_) external onlyOwner {
        uint _currentSupply_ = totalSupply();
        require(
            supply_ > _currentSupply_,
            "Max supply should be greater than current supply"
        );
        require(
            supply_ < maxSupply,
            "Max supply should be greater than previous max supply"
        );
        maxSupply = supply_;
    }

    /**
     * @dev set the merkle root for whitelist
     *
     * @param root_ : the merkle for whitelist
     */
    function setWhitelistRoot(bytes32 root_) external onlyOwner {
        _root = root_;
    }

    /**
     * @dev set the base uri for collection
     *
     * @param baseURI_ : the base uri for collection
     */
    function setBaseURI(string memory baseURI_) external onlyOwner {
        _setBaseURI(baseURI_);
    }

    /**
     * @dev set the sale state
     *
     * @param sale_ : the new sale state
     */
    function setSaleState(Sale sale_) external onlyOwner {
        saleState = sale_;
    }


    function mintWhitelist(bytes32[] memory proof_)
        external
        payable
        blockContracts
        isSaleState(Sale.PRIVATE)
    {
        if (_root == 0) {
            revert Whitelist_NOT_SET();
        }
        address account_ = msg.sender;
        if (_private_consumed[account_]) {
            revert Whitelist_CONSUMED(account_);
        }
        bytes32 leaf = keccak256(abi.encodePacked(account_));
        bool isAllowed =  MerkleProof.processProof(proof_, leaf) == _root;
        if (!isAllowed) {
            revert Whitelist_FORBIDDEN(account_);
        }
        uint _supply_ = totalSupply();
        require(_supply_ + maxPerWhitelist <= maxSupply, "Exceeds supply");
        require(
            msg.value == whitelistPrice,
            "Ether sent is not correct"
        );
        _mint(msg.sender, maxPerWhitelist);
       _private_consumed[account_] = true;
    }

    function mintNextWhitelist(bytes32[] memory proof_)
        external
        payable
        blockContracts
        isSaleState(Sale.PRIVATE_NEXT)
    {
        if (_root == 0) {
            revert Whitelist_NOT_SET();
        }
        address account_ = msg.sender;
        if (_private_next[account_]) {
            revert Whitelist_CONSUMED(account_);
        }
        bytes32 leaf = keccak256(abi.encodePacked(account_));
        bool isAllowed =  MerkleProof.processProof(proof_, leaf) == _root;
        if (!isAllowed) {
            revert Whitelist_FORBIDDEN(account_);
        }
        uint _supply_ = totalSupply();
        require(_supply_ + maxPerWhitelist <= maxSupply, "Exceeds supply");
        require(
            msg.value == whitelistPrice,
            "Ether sent is not correct"
        );
        _mint(msg.sender, maxPerWhitelist);
       _private_next[account_] = true;
    }

    /**
     * @dev mint the token for airdrop
     *
     * @param qty_ : the quantity of mint
     * @param to_: the address to send to
     */
    function airdrop( uint256 qty_ , address to_) onlyOwner
        external
        payable
        blockContracts
    {
        uint _supply_ = totalSupply();
        require(_supply_ + qty_ <= maxSupply, "Exceeds supply");
        _mint(to_, qty_);
    }

    /**
     * @dev mint the token in public sale
     *
     * @param qty_ : the quantity of mint
     */
    function mintPublic(uint256 qty_)
        external
        payable
        blockContracts
        isSaleState(Sale.PUBLIC)
    {
        uint _supply_ = totalSupply();
        require(
            mintedPerWallet[msg.sender] + qty_ <= maxPerPublic,
            "Exceeds mint per wallet"
        );
        require(_supply_ + qty_ <= maxSupply, "Exceeds supply");
        require(msg.value == qty_ * publicPrice, "Ether sent is not correct");
        _mint(msg.sender, qty_);
        mintedPerWallet[msg.sender] += qty_;
    }

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public override onlyAllowedOperator(from) {
        super.transferFrom(from, to, tokenId);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public override onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, tokenId);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public override onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, tokenId, data);
    }
}

File 2 of 14 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

        if (totalHashes > 0) {
            require(proofPos == proofLen, "MerkleProof: invalid multiproof");
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

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

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

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

        if (totalHashes > 0) {
            require(proofPos == proofLen, "MerkleProof: invalid multiproof");
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

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

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

File 3 of 14 : DefaultOperatorFilterer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

abstract contract DefaultOperatorFilterer is OperatorFilterer {
    address constant DEFAULT_SUBSCRIPTION = address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6);

    constructor() OperatorFilterer(DEFAULT_SUBSCRIPTION, true) {}
}

File 4 of 14 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

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

File 5 of 14 : IERC173.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/**
* @dev Required interface of an ERC173 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-173[EIP].
*/
interface IERC173 /* is IERC165 */ {
    /// @dev This emits when ownership of a contract changes.    
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// @notice Get the address of the owner    
    /// @return The address of the owner.
    function owner() view external returns(address);
	
    /// @notice Set the address of the new owner of the contract
    /// @dev Set _newOwner to address(0) to renounce any ownership.
    /// @param _newOwner The address of the new owner of the contract    
    function transferOwnership(address _newOwner) external;	
}

File 6 of 14 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

pragma solidity 0.8.17;

/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface IERC721 /* is IERC165 */ {
  /// @dev This emits when ownership of any NFT changes by any mechanism.
  ///  This event emits when NFTs are created (`from` == 0) and destroyed
  ///  (`to` == 0). Exception: during contract creation, any number of NFTs
  ///  may be created and assigned without emitting Transfer. At the time of
  ///  any transfer, the approved address for that NFT (if any) is reset to none.
  event Transfer( address indexed from_, address indexed to_, uint256 indexed tokenId_ );

  /// @dev This emits when the approved address for an NFT is changed or
  ///  reaffirmed. The zero address indicates there is no approved address.
  ///  When a Transfer event emits, this also indicates that the approved
  ///  address for that NFT (if any) is reset to none.
  event Approval( address indexed owner_, address indexed approved_, uint256 indexed tokenId_ );

  /// @dev This emits when an operator is enabled or disabled for an owner.
  ///  The operator can manage all NFTs of the owner.
  event ApprovalForAll( address indexed owner_, address indexed operator_, bool approved_ );

  /// @notice Count all NFTs assigned to an owner
  /// @dev NFTs assigned to the zero address are considered invalid, and this
  ///  function throws for queries about the zero address.
  /// @param owner_ An address for whom to query the balance
  /// @return The number of NFTs owned by `owner_`, possibly zero
  function balanceOf( address owner_ ) external view returns ( uint256 );

  /// @notice Find the owner of an NFT
  /// @dev NFTs assigned to zero address are considered invalid, and queries
  ///  about them do throw.
  /// @param tokenId_ The identifier for an NFT
  /// @return The address of the owner of the NFT
  function ownerOf( uint256 tokenId_ ) external view returns ( address );

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @dev Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `from_` is
  ///  not the current owner. Throws if `to_` is the zero address. Throws if
  ///  `tokenId_` is not a valid NFT. When transfer is complete, this function
  ///  checks if `to_` is a smart contract (code size > 0). If so, it calls
  ///  `onERC721Received` on `to_` and throws if the return value is not
  ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
  /// @param from_ The current owner of the NFT
  /// @param to_ The new owner
  /// @param tokenId_ The NFT to transfer
  /// @param data_ Additional data with no specified format, sent in call to `to_`
  function safeTransferFrom( address from_, address to_, uint256 tokenId_, bytes calldata data_ ) external;

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @dev This works identically to the other function with an extra data parameter,
  ///  except this function just sets data to "".
  /// @param from_ The current owner of the NFT
  /// @param to_ The new owner
  /// @param tokenId_ The NFT to transfer
  function safeTransferFrom( address from_, address to_, uint256 tokenId_ ) external;

  /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
  ///  TO CONFIRM THAT `to_` IS CAPABLE OF RECEIVING NFTS OR ELSE
  ///  THEY MAY BE PERMANENTLY LOST
  /// @dev Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `from_` is
  ///  not the current owner. Throws if `to_` is the zero address. Throws if
  ///  `tokenId_` is not a valid NFT.
  /// @param from_ The current owner of the NFT
  /// @param to_ The new owner
  /// @param tokenId_ The NFT to transfer
  function transferFrom( address from_, address to_, uint256 tokenId_ ) external;

  /// @notice Change or reaffirm the approved address for an NFT
  /// @dev The zero address indicates there is no approved address.
  ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
  ///  operator of the current owner.
  /// @param approved_ The new approved NFT controller
  /// @param tokenId_ The NFT to approve
  function approve( address approved_, uint256 tokenId_ ) external;

  /// @notice Enable or disable approval for a third party ("operator") to manage
  ///  all of `msg.sender`'s assets
  /// @dev Emits the ApprovalForAll event. The contract MUST allow
  ///  multiple operators per owner.
  /// @param operator_ Address to add to the set of authorized operators
  /// @param approved_ True if the operator is approved, false to revoke approval
  function setApprovalForAll( address operator_, bool approved_ ) external;

  /// @notice Get the approved address for a single NFT
  /// @dev Throws if `tokenId_` is not a valid NFT.
  /// @param tokenId_ The NFT to find the approved address for
  /// @return The approved address for this NFT, or the zero address if there is none
  function getApproved( uint256 tokenId_ ) external view returns ( address );

  /// @notice Query if an address is an authorized operator for another address
  /// @param owner_ The address that owns the NFTs
  /// @param operator_ The address that acts on behalf of the owner
  /// @return True if `operator_` is an approved operator for `owner_`, false otherwise
  function isApprovedForAll( address owner_, address operator_ ) external view returns ( bool );
}

File 7 of 14 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x780e9d63.
interface IERC721Enumerable /* is IERC721 */ {
    /// @notice Count NFTs tracked by this contract
    /// @return A count of valid NFTs tracked by this contract, where each one of
    ///  them has an assigned and queryable owner not equal to the zero address
    function totalSupply() external view returns ( uint256 );

    /// @notice Enumerate valid NFTs
    /// @dev Throws if `index_` >= `totalSupply()`.
    /// @param index_ A counter less than `totalSupply()`
    /// @return The token identifier for the `index_`th NFT,
    ///  (sort order not specified)
    function tokenByIndex( uint256 index_ ) external view returns ( uint256 );

    /// @notice Enumerate NFTs assigned to an owner
    /// @dev Throws if `index_` >= `balanceOf(owner_)` or if
    ///  `owner_` is the zero address, representing invalid NFTs.
    /// @param owner_ An address where we are interested in NFTs owned by them
    /// @param index_ A counter less than `balanceOf(owner_)`
    /// @return The token identifier for the `index_`th NFT assigned to `owner_`,
    ///   (sort order not specified)
    function tokenOfOwnerByIndex( address owner_, uint256 index_ ) external view returns ( uint256 );
}

File 8 of 14 : IERC721Errors.sol
// SPDX-License-Identifier: MIT

/**
* Author: Lambdalf the White
*/

pragma solidity 0.8.17;

interface IERC721Errors {
  /**
  * @dev Thrown when `operator` has not been approved to manage `tokenId` on behalf of `tokenOwner`.
  * 
  * @param tokenOwner : address owning the token
  * @param operator   : address trying to manage the token
  * @param tokenId    : identifier of the NFT being referenced
  */
  error IERC721_CALLER_NOT_APPROVED( address tokenOwner, address operator, uint256 tokenId );
  /**
  * @dev Thrown when `operator` tries to approve themselves for managing a token they own.
  * 
  * @param operator : address that is trying to approve themselves
  */
  error IERC721_INVALID_APPROVAL( address operator );
  /**
  * @dev Thrown when a token is being transferred to the zero address.
  */
  error IERC721_INVALID_TRANSFER();
  /**
  * @dev Thrown when a token is being transferred from an address that doesn't own it.
  * 
  * @param tokenOwner : address owning the token
  * @param from       : address that the NFT is being transferred from
  * @param tokenId    : identifier of the NFT being referenced
  */
  error IERC721_INVALID_TRANSFER_FROM( address tokenOwner, address from, uint256 tokenId );
  /**
  * @dev Thrown when the requested token doesn't exist.
  * 
  * @param tokenId : identifier of the NFT being referenced
  */
  error IERC721_NONEXISTANT_TOKEN( uint256 tokenId );
  /**
  * @dev Thrown when a token is being safely transferred to a contract unable to handle it.
  * 
  * @param receiver : address unable to receive the token
  */
  error IERC721_NON_ERC721_RECEIVER( address receiver );
  /**
  * @dev Thrown when trying to get the token at an index that doesn't exist.
  * 
  * @param index : the inexistant index
  */
  error IERC721Enumerable_INDEX_OUT_OF_BOUNDS( uint256 index );
  /**
  * @dev Thrown when trying to get the token owned by `tokenOwner` at an index that doesn't exist.
  * 
  * @param tokenOwner : address owning the token
  * @param index      : the inexistant index
  */
  error IERC721Enumerable_OWNER_INDEX_OUT_OF_BOUNDS( address tokenOwner, uint256 index );
}

File 9 of 14 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x5b5e139f.
interface IERC721Metadata /* is IERC721 */ {
    /// @notice A descriptive name for a collection of NFTs in this contract
    function name() external view returns ( string memory _name );

    /// @notice An abbreviated name for NFTs in this contract
    function symbol() external view returns ( string memory _symbol );

    /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
    /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
    ///  3986. The URI may point to a JSON file that conforms to the "ERC721
    ///  Metadata JSON Schema".
    function tokenURI( uint256 _tokenId ) external view returns ( string memory );
}

File 10 of 14 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface IERC721Receiver {
    /// @notice Handle the receipt of an NFT
    /// @dev The ERC721 smart contract calls this function on the recipient
    ///  after a `transfer`. This function MAY throw to revert and reject the
    ///  transfer. Return of other than the magic value MUST result in the
    ///  transaction being reverted.
    ///  Note: the contract address is always the message sender.
    /// @param operator_ The address which called `safeTransferFrom` function
    /// @param from_ The address which previously owned the token
    /// @param tokenId_ The NFT identifier which is being transferred
    /// @param data_ Additional data with no specified format
    /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    ///  unless throwing
    function onERC721Received( address operator_, address from_, uint256 tokenId_, bytes calldata data_ ) external returns( bytes4 );
}

File 11 of 14 : IOperatorFilterRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

interface IOperatorFilterRegistry {
    function isOperatorAllowed(address registrant, address operator)
        external
        view
        returns (bool);

    function register(address registrant) external;

    function registerAndSubscribe(address registrant, address subscription)
        external;

    function registerAndCopyEntries(
        address registrant,
        address registrantToCopy
    ) external;

    function updateOperator(
        address registrant,
        address operator,
        bool filtered
    ) external;

    function updateOperators(
        address registrant,
        address[] calldata operators,
        bool filtered
    ) external;

    function updateCodeHash(
        address registrant,
        bytes32 codehash,
        bool filtered
    ) external;

    function updateCodeHashes(
        address registrant,
        bytes32[] calldata codeHashes,
        bool filtered
    ) external;

    function subscribe(address registrant, address registrantToSubscribe)
        external;

    function unsubscribe(address registrant, bool copyExistingEntries) external;

    function subscriptionOf(address addr) external returns (address registrant);

    function subscribers(address registrant)
        external
        returns (address[] memory);

    function subscriberAt(address registrant, uint256 index)
        external
        returns (address);

    function copyEntriesOf(address registrant, address registrantToCopy)
        external;

    function isOperatorFiltered(address registrant, address operator)
        external
        returns (bool);

    function isCodeHashOfFiltered(address registrant, address operatorWithCode)
        external
        returns (bool);

    function isCodeHashFiltered(address registrant, bytes32 codeHash)
        external
        returns (bool);

    function filteredOperators(address addr)
        external
        returns (address[] memory);

    function filteredCodeHashes(address addr)
        external
        returns (bytes32[] memory);

    function filteredOperatorAt(address registrant, uint256 index)
        external
        returns (address);

    function filteredCodeHashAt(address registrant, uint256 index)
        external
        returns (bytes32);

    function isRegistered(address addr) external returns (bool);

    function codeHashOf(address addr) external returns (bytes32);
}

File 12 of 14 : OperatorFilterer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

abstract contract OperatorFilterer {
    error OperatorNotAllowed(address operator);

    IOperatorFilterRegistry constant operatorFilterRegistry =
        IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);

    constructor(address subscriptionOrRegistrantToCopy, bool subscribe) {
        // If an inheriting token contract is deployed to a network without the registry deployed, the modifier
        // will not revert, but the contract will need to be registered with the registry once it is deployed in
        // order for the modifier to filter addresses.
        if (address(operatorFilterRegistry).code.length > 0) {
            if (subscribe) {
                operatorFilterRegistry.registerAndSubscribe(
                    address(this),
                    subscriptionOrRegistrantToCopy
                );
            } else {
                if (subscriptionOrRegistrantToCopy != address(0)) {
                    operatorFilterRegistry.registerAndCopyEntries(
                        address(this),
                        subscriptionOrRegistrantToCopy
                    );
                } else {
                    operatorFilterRegistry.register(address(this));
                }
            }
        }
    }

    modifier onlyAllowedOperator(address from) virtual {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (address(operatorFilterRegistry).code.length > 0) {
            // Allow spending tokens from addresses with balance
            // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred
            // from an EOA.
            if (from == msg.sender) {
                _;
                return;
            }
            if (
                !(operatorFilterRegistry.isOperatorAllowed(
                    address(this),
                    msg.sender
                ) &&
                    operatorFilterRegistry.isOperatorAllowed(
                        address(this),
                        from
                    ))
            ) {
                revert OperatorNotAllowed(msg.sender);
            }
        }
        _;
    }
}

File 13 of 14 : Reg_ERC721Batch.sol
// SPDX-License-Identifier: MIT

/**
 * Author: Lambdalf the White
 */

pragma solidity 0.8.17;

import "./interfaces/IERC721Errors.sol";
import "./interfaces/IERC165.sol";
import "./interfaces/IERC721.sol";
import "./interfaces/IERC721Enumerable.sol";
import "./interfaces/IERC721Metadata.sol";
import "./interfaces/IERC721Receiver.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 * This contract features:
 * ~ Very Cheap batch minting
 * ~ Token tracker support
 *
 * Note: This implementation imposes a very expensive `balanceOf()` and `ownerOf()`.
 * It is not recommended to interract with those from another contract.
 */
abstract contract Reg_ERC721Batch is
    IERC721Errors,
    IERC165,
    IERC721,
    IERC721Metadata,
    IERC721Enumerable
{
    uint256 private _nextId = 1;
    string public name;
    string public symbol;

    // Mapping from token ID to approved address
    mapping(uint256 => address) public getApproved;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    // List of owner addresses
    mapping(uint256 => address) private _owners;

    // Token Base URI
    string private _baseURI;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    function __init_ERC721Metadata(
        string memory name_,
        string memory symbol_,
        string memory baseURI_
    ) internal {
        name = name_;
        symbol = symbol_;
        _baseURI = baseURI_;
    }

    // **************************************
    // *****          MODIFIER          *****
    // **************************************
    /**
     * @dev Ensures the token exist.
     * A token exists if it has been minted and is not owned by the null address.
     *
     * @param tokenId_ : identifier of the NFT being referenced
     */
    modifier exists(uint256 tokenId_) {
        if (!_exists(tokenId_)) {
            revert IERC721_NONEXISTANT_TOKEN(tokenId_);
        }
        _;
    }

    // **************************************

    // **************************************
    // *****          INTERNAL          *****
    // **************************************
    /**
     * @dev Internal function returning the number of tokens in `tokenOwner_`'s account.
     */
    function _balanceOf(address tokenOwner_)
        internal
        view
        virtual
        returns (uint256)
    {
        if (tokenOwner_ == address(0)) {
            return 0;
        }

        uint256 _count_ = 0;
        address _currentTokenOwner_;
        for (uint256 i = 1; i < _nextId; ++i) {
            if (_exists(i)) {
                if (_owners[i] != address(0)) {
                    _currentTokenOwner_ = _owners[i];
                }
                if (tokenOwner_ == _currentTokenOwner_) {
                    _count_++;
                }
            }
        }
        return _count_;
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from_ address representing the previous owner of the given token ID
     * @param to_ target address that will receive the tokens
     * @param tokenId_ uint256 ID of the token to be transferred
     * @param data_ bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from_,
        address to_,
        uint256 tokenId_,
        bytes memory data_
    ) internal virtual returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.
        //
        // IMPORTANT
        // It is unsafe to assume that an address not flagged by this method
        // is an externally-owned account (EOA) and not a contract.
        //
        // Among others, the following types of addresses will not be flagged:
        //
        //  - an externally-owned account
        //  - a contract in construction
        //  - an address where a contract will be created
        //  - an address where a contract lived, but was destroyed
        uint256 _size_;
        assembly {
            _size_ := extcodesize(to_)
        }

        // If address is a contract, check that it is aware of how to handle ERC721 tokens
        if (_size_ > 0) {
            try
                IERC721Receiver(to_).onERC721Received(
                    msg.sender,
                    from_,
                    tokenId_,
                    data_
                )
            returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert IERC721_NON_ERC721_RECEIVER(to_);
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Internal function returning whether a token exists.
     * A token exists if it has been minted and is not owned by the null address.
     *
     * @param tokenId_ uint256 ID of the token to verify
     *
     * @return bool whether the token exists
     */
    function _exists(uint256 tokenId_) internal view virtual returns (bool) {
        if (tokenId_ == 0) {
            return false;
        }
        return tokenId_ < _nextId;
    }

    /**
     * @dev Internal function returning whether `operator_` is allowed
     * to manage tokens on behalf of `tokenOwner_`.
     *
     * @param tokenOwner_ address that owns tokens
     * @param operator_ address that tries to manage tokens
     *
     * @return bool whether `operator_` is allowed to handle the token
     */
    function _isApprovedForAll(address tokenOwner_, address operator_)
        internal
        view
        virtual
        returns (bool)
    {
        return _operatorApprovals[tokenOwner_][operator_];
    }

    /**
     * @dev Internal function returning whether `operator_` is allowed to handle `tokenId_`
     *
     * Note: To avoid multiple checks for the same data, it is assumed that existence of `tokeId_`
     * has been verified prior via {_exists}
     * If it hasn't been verified, this function might panic
     *
     * @param operator_ address that tries to handle the token
     * @param tokenId_ uint256 ID of the token to be handled
     *
     * @return bool whether `operator_` is allowed to handle the token
     */
    function _isApprovedOrOwner(
        address tokenOwner_,
        address operator_,
        uint256 tokenId_
    ) internal view virtual returns (bool) {
        bool _isApproved_ = operator_ == tokenOwner_ ||
            operator_ == getApproved[tokenId_] ||
            _isApprovedForAll(tokenOwner_, operator_);
        return _isApproved_;
    }

    /**
     * @dev Mints `qty_` tokens and transfers them to `to_`.
     *
     * This internal function can be used to perform token minting.
     *
     * Emits one or more {Transfer} event.
     */
    function _mint(address to_, uint256 qty_) internal virtual {
        uint256 _firstToken_ = _nextId;
        uint256 _nextStart_ = _firstToken_ + qty_;
        uint256 _lastToken_ = _nextStart_ - 1;

        _owners[_firstToken_] = to_;
        if (_lastToken_ > _firstToken_) {
            _owners[_lastToken_] = to_;
        }
        _nextId = _nextStart_;

        if (!_checkOnERC721Received(address(0), to_, _firstToken_, "")) {
            revert IERC721_NON_ERC721_RECEIVER(to_);
        }

        for (uint256 i = _firstToken_; i < _nextStart_; ++i) {
            emit Transfer(address(0), to_, i);
        }
    }

    /**
     * @dev Internal function returning the owner of the `tokenId_` token.
     *
     * @param tokenId_ uint256 ID of the token to verify
     *
     * @return address the address of the token owner
     */
    function _ownerOf(uint256 tokenId_)
        internal
        view
        virtual
        returns (address)
    {
        uint256 _tokenId_ = tokenId_;
        address _tokenOwner_ = _owners[_tokenId_];
        while (_tokenOwner_ == address(0)) {
            _tokenId_--;
            _tokenOwner_ = _owners[_tokenId_];
        }

        return _tokenOwner_;
    }

    /**
     * @dev Internal function used to set the base URI of the collection.
     */
    function _setBaseURI(string memory baseURI_) internal virtual {
        _baseURI = baseURI_;
    }

    /**
     * @dev Internal function returning the total supply.
     */
    function _totalSupply() internal view virtual returns (uint256) {
        return supplyMinted();
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function _toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Transfers `tokenId_` from `from_` to `to_`.
     *
     * This internal function can be used to implement alternative mechanisms to perform
     * token transfer, such as signature-based, or token burning.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from_,
        address to_,
        uint256 tokenId_
    ) internal virtual {
        getApproved[tokenId_] = address(0);
        uint256 _previousId_ = tokenId_ > 1 ? tokenId_ - 1 : 1;
        uint256 _nextId_ = tokenId_ + 1;
        bool _previousShouldUpdate_ = _previousId_ < tokenId_ &&
            _exists(_previousId_) &&
            _owners[_previousId_] == address(0);
        bool _nextShouldUpdate_ = _exists(_nextId_) &&
            _owners[_nextId_] == address(0);

        if (_previousShouldUpdate_) {
            _owners[_previousId_] = from_;
        }

        if (_nextShouldUpdate_) {
            _owners[_nextId_] = from_;
        }

        _owners[tokenId_] = to_;

        emit Transfer(from_, to_, tokenId_);
    }

    // **************************************

    // **************************************
    // *****           PUBLIC           *****
    // **************************************
    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to_, uint256 tokenId_)
        public
        virtual
        exists(tokenId_)
    {
        address _operator_ = msg.sender;
        address _tokenOwner_ = _ownerOf(tokenId_);
        if (to_ == _tokenOwner_) {
            revert IERC721_INVALID_APPROVAL(to_);
        }

        bool _isApproved_ = _isApprovedOrOwner(
            _tokenOwner_,
            _operator_,
            tokenId_
        );
        if (!_isApproved_) {
            revert IERC721_CALLER_NOT_APPROVED(
                _tokenOwner_,
                _operator_,
                tokenId_
            );
        }

        getApproved[tokenId_] = to_;
        emit Approval(_tokenOwner_, to_, tokenId_);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     *
     * Note: We can ignore `from_` as we can compare everything to the actual token owner,
     * but we cannot remove this parameter to stay in conformity with IERC721
     */
    function safeTransferFrom(
        address from_,
        address to_,
        uint256 tokenId_
    ) public virtual override {
        safeTransferFrom(from_, to_, tokenId_, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     *
     * Note: We can ignore `from_` as we can compare everything to the actual token owner,
     * but we cannot remove this parameter to stay in conformity with IERC721
     */
    function safeTransferFrom(
        address from_,
        address to_,
        uint256 tokenId_,
        bytes memory data_
    ) public virtual override {
        transferFrom(from_, to_, tokenId_);
        if (!_checkOnERC721Received(from_, to_, tokenId_, data_)) {
            revert IERC721_NON_ERC721_RECEIVER(to_);
        }
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator_, bool approved_)
        public
        virtual
        override
    {
        address _account_ = msg.sender;
        if (operator_ == _account_) {
            revert IERC721_INVALID_APPROVAL(operator_);
        }

        _operatorApprovals[_account_][operator_] = approved_;
        emit ApprovalForAll(_account_, operator_, approved_);
    }

    /**
     * @dev See {IERC721-transferFrom}.
     *
     * Note: We can ignore `from_` as we can compare everything to the actual token owner,
     * but we cannot remove this parameter to stay in conformity with IERC721
     */
    function transferFrom(
        address from_,
        address to_,
        uint256 tokenId_
    ) public virtual exists(tokenId_) {
        if (to_ == address(0)) {
            revert IERC721_INVALID_TRANSFER();
        }

        address _operator_ = msg.sender;
        address _tokenOwner_ = _ownerOf(tokenId_);
        if (from_ != _tokenOwner_) {
            revert IERC721_INVALID_TRANSFER_FROM(_tokenOwner_, from_, tokenId_);
        }

        bool _isApproved_ = _isApprovedOrOwner(
            _tokenOwner_,
            _operator_,
            tokenId_
        );
        if (!_isApproved_) {
            revert IERC721_CALLER_NOT_APPROVED(
                _tokenOwner_,
                _operator_,
                tokenId_
            );
        }

        _transfer(_tokenOwner_, to_, tokenId_);
    }

    // **************************************

    // **************************************
    // *****            VIEW            *****
    // **************************************
    /**
     * @dev Returns the number of tokens in `tokenOwner_`'s account.
     */
    function balanceOf(address tokenOwner_)
        public
        view
        virtual
        returns (uint256)
    {
        return _balanceOf(tokenOwner_);
    }

    /**
     * @dev Returns if the `operator_` is allowed to manage all of the assets of `tokenOwner_`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address tokenOwner_, address operator_)
        public
        view
        virtual
        returns (bool)
    {
        return _isApprovedForAll(tokenOwner_, operator_);
    }

    /**
     * @dev Returns the owner of the `tokenId_` token.
     *
     * Requirements:
     *
     * - `tokenId_` must exist.
     */
    function ownerOf(uint256 tokenId_)
        public
        view
        virtual
        exists(tokenId_)
        returns (address)
    {
        return _ownerOf(tokenId_);
    }

    /**
     * @dev Returns the total number of tokens minted
     *
     * @return uint256 the number of tokens that have been minted so far
     */
    function supplyMinted() public view virtual returns (uint256) {
        return _nextId - 1;
    }

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

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index_)
        public
        view
        virtual
        override
        returns (uint256)
    {
        if (index_ >= supplyMinted()) {
            revert IERC721Enumerable_INDEX_OUT_OF_BOUNDS(index_);
        }
        return index_ + 1;
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address tokenOwner_, uint256 index_)
        public
        view
        virtual
        override
        returns (uint256 tokenId)
    {
        if (index_ >= _balanceOf(tokenOwner_)) {
            revert IERC721Enumerable_OWNER_INDEX_OUT_OF_BOUNDS(
                tokenOwner_,
                index_
            );
        }

        uint256 _count_ = 0;
        for (uint256 i = 1; i < _nextId; i++) {
            if (_exists(i) && tokenOwner_ == _ownerOf(i)) {
                if (index_ == _count_) {
                    return i;
                }
                _count_++;
            }
        }
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId_)
        public
        view
        virtual
        override
        exists(tokenId_)
        returns (string memory)
    {
        return
            bytes(_baseURI).length > 0
                ? string(abi.encodePacked(_baseURI, _toString(tokenId_)))
                : _toString(tokenId_);
    }

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

File 14 of 14 : ERC173.sol
// SPDX-License-Identifier: MIT

/**
* Author: Lambdalf the White
*/

pragma solidity 0.8.17;

import "../interfaces/IERC173.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.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract ERC173 is IERC173 {
	// Errors
  /**
  * @dev Thrown when `operator` is not the contract owner.
  * 
  * @param operator : address trying to use a function reserved to contract owner without authorization
  */
  error IERC173_NOT_OWNER( address operator );

	// The owner of the contract
	address private _owner;

	/**
	* @dev Throws if called by any account other than the owner.
	*/
	modifier onlyOwner() {
		address _sender_ = msg.sender;
		if ( owner() != _sender_ ) {
			revert IERC173_NOT_OWNER( _sender_ );
		}
		_;
	}

	/**
	* @dev Sets the contract owner.
	* 
	* Note: This function needs to be called in the contract constructor to initialize the contract owner, 
	* if it is not, then parts of the contract might be non functional
	* 
	* @param owner_ : address that owns the contract
	*/
	function _setOwner( address owner_ ) internal {
		_owner = owner_;
	}

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

	/**
	* @dev Transfers ownership of the contract to `newOwner_`.
	* 
	* @param newOwner_ : address of the new contract owner
	* 
	* Requirements:
	* 
  * - Caller must be the contract owner.
	*/
	function transferOwnership( address newOwner_ ) public virtual onlyOwner {
		address _oldOwner_ = _owner;
		_owner = newOwner_;
		emit OwnershipTransferred( _oldOwner_, newOwner_ );
	}
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"string","name":"baseURI_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"IERC173_NOT_OWNER","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"IERC721Enumerable_INDEX_OUT_OF_BOUNDS","type":"error"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"IERC721Enumerable_OWNER_INDEX_OUT_OF_BOUNDS","type":"error"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"IERC721_CALLER_NOT_APPROVED","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"IERC721_INVALID_APPROVAL","type":"error"},{"inputs":[],"name":"IERC721_INVALID_TRANSFER","type":"error"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"IERC721_INVALID_TRANSFER_FROM","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"IERC721_NONEXISTANT_TOKEN","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"IERC721_NON_ERC721_RECEIVER","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"Whitelist_CONSUMED","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"Whitelist_FORBIDDEN","type":"error"},{"inputs":[],"name":"Whitelist_NOT_SET","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner_","type":"address"},{"indexed":true,"internalType":"address","name":"approved_","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner_","type":"address"},{"indexed":true,"internalType":"address","name":"operator_","type":"address"},{"indexed":false,"internalType":"bool","name":"approved_","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from_","type":"address"},{"indexed":true,"internalType":"address","name":"to_","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"uint256","name":"qty_","type":"uint256"},{"internalType":"address","name":"to_","type":"address"}],"name":"airdrop","outputs":[],"stateMutability":"payable","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":"tokenOwner_","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOwner_","type":"address"},{"internalType":"address","name":"operator_","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPerPublic","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPerWhitelist","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof_","type":"bytes32[]"}],"name":"mintNextWhitelist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"qty_","type":"uint256"}],"name":"mintPublic","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof_","type":"bytes32[]"}],"name":"mintWhitelist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintedPerWallet","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":[],"name":"publicPrice","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":[],"name":"saleState","outputs":[{"internalType":"enum UndeadChef.Sale","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"supply_","type":"uint256"}],"name":"setMaxSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mints_","type":"uint256"}],"name":"setMintsPerPublic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mints_","type":"uint256"}],"name":"setMintsPerWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price_","type":"uint256"}],"name":"setPublicPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum UndeadChef.Sale","name":"sale_","type":"uint8"}],"name":"setSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price_","type":"uint256"}],"name":"setWhitelistPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root_","type":"bytes32"}],"name":"setWhitelistRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"tokenOwner_","type":"address"},{"internalType":"uint256","name":"index_","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner_","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"whitelistPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405260016000556611c37937e080006008556611c37937e080006009556003600a556003600b55610fa0600c556000601060006101000a81548160ff021916908360038111156200005857620000576200034a565b5b02179055503480156200006a57600080fd5b50604051620057d6380380620057d683398181016040528101906200009091906200050c565b733cc6cdda760b79bafa08df41ecfa224f810dceb6600160006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156200029c57801562000162576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff16637d3e3dbe30846040518363ffffffff1660e01b8152600401620001289291906200060a565b600060405180830381600087803b1580156200014357600080fd5b505af115801562000158573d6000803e3d6000fd5b505050506200029b565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146200021c576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663a0af290330846040518363ffffffff1660e01b8152600401620001e29291906200060a565b600060405180830381600087803b158015620001fd57600080fd5b505af115801562000212573d6000803e3d6000fd5b505050506200029a565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff16634420e486306040518263ffffffff1660e01b815260040162000265919062000637565b600060405180830381600087803b1580156200028057600080fd5b505af115801562000295573d6000803e3d6000fd5b505050505b5b5b5050620002b1838383620002cb60201b60201c565b620002c2336200030660201b60201c565b50505062000986565b8260019081620002dc91906200089f565b508160029081620002ee91906200089f565b5080600690816200030091906200089f565b50505050565b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620003e28262000397565b810181811067ffffffffffffffff82111715620004045762000403620003a8565b5b80604052505050565b60006200041962000379565b9050620004278282620003d7565b919050565b600067ffffffffffffffff8211156200044a5762000449620003a8565b5b620004558262000397565b9050602081019050919050565b60005b838110156200048257808201518184015260208101905062000465565b60008484015250505050565b6000620004a56200049f846200042c565b6200040d565b905082815260208101848484011115620004c457620004c362000392565b5b620004d184828562000462565b509392505050565b600082601f830112620004f157620004f06200038d565b5b8151620005038482602086016200048e565b91505092915050565b60008060006060848603121562000528576200052762000383565b5b600084015167ffffffffffffffff81111562000549576200054862000388565b5b6200055786828701620004d9565b935050602084015167ffffffffffffffff8111156200057b576200057a62000388565b5b6200058986828701620004d9565b925050604084015167ffffffffffffffff811115620005ad57620005ac62000388565b5b620005bb86828701620004d9565b9150509250925092565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620005f282620005c5565b9050919050565b6200060481620005e5565b82525050565b6000604082019050620006216000830185620005f9565b620006306020830184620005f9565b9392505050565b60006020820190506200064e6000830184620005f9565b92915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620006a757607f821691505b602082108103620006bd57620006bc6200065f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620007277fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620006e8565b620007338683620006e8565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620007806200077a62000774846200074b565b62000755565b6200074b565b9050919050565b6000819050919050565b6200079c836200075f565b620007b4620007ab8262000787565b848454620006f5565b825550505050565b600090565b620007cb620007bc565b620007d881848462000791565b505050565b5b818110156200080057620007f4600082620007c1565b600181019050620007de565b5050565b601f8211156200084f576200081981620006c3565b6200082484620006d8565b8101602085101562000834578190505b6200084c6200084385620006d8565b830182620007dd565b50505b505050565b600082821c905092915050565b6000620008746000198460080262000854565b1980831691505092915050565b60006200088f838362000861565b9150826002028217905092915050565b620008aa8262000654565b67ffffffffffffffff811115620008c657620008c5620003a8565b5b620008d282546200068e565b620008df82828562000804565b600060209050601f83116001811462000917576000841562000902578287015190505b6200090e858262000881565b8655506200097e565b601f1984166200092786620006c3565b60005b8281101562000951578489015182556001820191506020850194506020810190506200092a565b868310156200097157848901516200096d601f89168262000861565b8355505b6001600288020188555050505b505050505050565b614e4080620009966000396000f3fe6080604052600436106102305760003560e01c806370a082311161012e578063c87b56dd116100ab578063efd0cbf91161006f578063efd0cbf914610848578063f2fde38b14610864578063f3fef3a31461088d578063f5aa406d146108b6578063fc1a1c36146108df57610230565b8063c87b56dd1461074f578063c95d83c61461078c578063cfe1908d146107b5578063d5abeb01146107e0578063e985e9c51461080b57610230565b8063a22cb465116100f2578063a22cb4651461068d578063a945bf80146106b6578063b88d4fde146106e1578063bc63f02e1461070a578063c62752551461072657610230565b806370a08231146105a6578063717d57d3146105e35780637e9845f51461060c5780638da5cb5b1461063757806395d89b411461066257610230565b80633a602b4d116101bc5780635a67de07116101805780635a67de07146104c1578063603f4d52146104ea5780636352211e1461051557806366cc5f0d146105525780636f8b44b01461057d57610230565b80633a602b4d146103d957806342842e0e1461041657806344d843811461043f5780634f6ccce71461045b57806355f804b31461049857610230565b8063095ea7b311610203578063095ea7b31461030357806318160ddd1461032c57806323b872dd1461035757806328bb1a2e146103805780632f745c591461039c57610230565b806301ffc9a71461023557806302c366bc1461027257806306fdde031461029b578063081812fc146102c6575b600080fd5b34801561024157600080fd5b5061025c60048036038101906102579190613894565b61090a565b60405161026991906138dc565b60405180910390f35b34801561027e57600080fd5b506102996004803603810190610294919061392d565b610aac565b005b3480156102a757600080fd5b506102b0610b33565b6040516102bd91906139ea565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e8919061392d565b610bc1565b6040516102fa9190613a4d565b60405180910390f35b34801561030f57600080fd5b5061032a60048036038101906103259190613a94565b610bf4565b005b34801561033857600080fd5b50610341610dcb565b60405161034e9190613ae3565b60405180910390f35b34801561036357600080fd5b5061037e60048036038101906103799190613afe565b610dda565b005b61039a60048036038101906103959190613ccf565b610fbc565b005b3480156103a857600080fd5b506103c360048036038101906103be9190613a94565b611300565b6040516103d09190613ae3565b60405180910390f35b3480156103e557600080fd5b5061040060048036038101906103fb9190613d18565b6113eb565b60405161040d9190613ae3565b60405180910390f35b34801561042257600080fd5b5061043d60048036038101906104389190613afe565b611403565b005b61045960048036038101906104549190613ccf565b6115e5565b005b34801561046757600080fd5b50610482600480360381019061047d919061392d565b611929565b60405161048f9190613ae3565b60405180910390f35b3480156104a457600080fd5b506104bf60048036038101906104ba9190613dfa565b61198a565b005b3480156104cd57600080fd5b506104e860048036038101906104e39190613e68565b611a13565b005b3480156104f657600080fd5b506104ff611abd565b60405161050c9190613f0c565b60405180910390f35b34801561052157600080fd5b5061053c6004803603810190610537919061392d565b611ad0565b6040516105499190613a4d565b60405180910390f35b34801561055e57600080fd5b50610567611b2e565b6040516105749190613ae3565b60405180910390f35b34801561058957600080fd5b506105a4600480360381019061059f919061392d565b611b34565b005b3480156105b257600080fd5b506105cd60048036038101906105c89190613d18565b611c4e565b6040516105da9190613ae3565b60405180910390f35b3480156105ef57600080fd5b5061060a6004803603810190610605919061392d565b611c60565b005b34801561061857600080fd5b50610621611ce7565b60405161062e9190613ae3565b60405180910390f35b34801561064357600080fd5b5061064c611cfd565b6040516106599190613a4d565b60405180910390f35b34801561066e57600080fd5b50610677611d27565b60405161068491906139ea565b60405180910390f35b34801561069957600080fd5b506106b460048036038101906106af9190613f53565b611db5565b005b3480156106c257600080fd5b506106cb611f28565b6040516106d89190613ae3565b60405180910390f35b3480156106ed57600080fd5b5061070860048036038101906107039190614034565b611f2e565b005b610724600480360381019061071f91906140b7565b612113565b005b34801561073257600080fd5b5061074d6004803603810190610748919061392d565b612269565b005b34801561075b57600080fd5b506107766004803603810190610771919061392d565b6122f0565b60405161078391906139ea565b60405180910390f35b34801561079857600080fd5b506107b360048036038101906107ae919061392d565b612395565b005b3480156107c157600080fd5b506107ca61241c565b6040516107d79190613ae3565b60405180910390f35b3480156107ec57600080fd5b506107f5612422565b6040516108029190613ae3565b60405180910390f35b34801561081757600080fd5b50610832600480360381019061082d91906140f7565b612428565b60405161083f91906138dc565b60405180910390f35b610862600480360381019061085d919061392d565b61243c565b005b34801561087057600080fd5b5061088b60048036038101906108869190613d18565b6126c0565b005b34801561089957600080fd5b506108b460048036038101906108af9190613a94565b612803565b005b3480156108c257600080fd5b506108dd60048036038101906108d89190614137565b6129c3565b005b3480156108eb57600080fd5b506108f4612a4a565b6040516109019190613ae3565b60405180910390f35b60007f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806109d557507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a3d57507f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610aa557507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16610ad0611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614610b2857806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401610b1f9190613a4d565b60405180910390fd5b81600b819055505050565b60018054610b4090614193565b80601f0160208091040260200160405190810160405280929190818152602001828054610b6c90614193565b8015610bb95780601f10610b8e57610100808354040283529160200191610bb9565b820191906000526020600020905b815481529060010190602001808311610b9c57829003601f168201915b505050505081565b60036020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b80610bfe81612a50565b610c3f57806040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600401610c369190613ae3565b60405180910390fd5b60003390506000610c4f84612a6f565b90508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610cc157846040517ff2b21e1c000000000000000000000000000000000000000000000000000000008152600401610cb89190613a4d565b60405180910390fd5b6000610cce828487612b35565b905080610d16578183866040517f19f48dff000000000000000000000000000000000000000000000000000000008152600401610d0d939291906141c4565b60405180910390fd5b856003600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050505050565b6000610dd5612bee565b905090565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115610faa573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e4c57610e47848484612bfd565b610fb6565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401610e959291906141fb565b602060405180830381865afa158015610eb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed69190614239565b8015610f6857506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401610f269291906141fb565b602060405180830381865afa158015610f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190614239565b5b610fa957336040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401610fa09190613a4d565b60405180910390fd5b5b610fb5848484612bfd565b5b50505050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff161461102a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611021906142b2565b60405180910390fd5b600280600381111561103f5761103e613e95565b5b601060009054906101000a900460ff16600381111561106157611060613e95565b5b146110a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110989061431e565b60405180910390fd5b6000801b600d54036110df576040517f93dff14200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000339050600f60008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561117357806040517f6acdb09500000000000000000000000000000000000000000000000000000000815260040161116a9190613a4d565b60405180910390fd5b6000816040516020016111869190614386565b6040516020818303038152906040528051906020012090506000600d546111ad8684612d9d565b149050806111f257826040517f186a628d0000000000000000000000000000000000000000000000000000000081526004016111e99190613a4d565b60405180910390fd5b60006111fc610dcb565b9050600c54600a548261120f91906143d0565b1115611250576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124790614450565b60405180910390fd5b6008543414611294576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128b906144bc565b60405180910390fd5b6112a033600a54612df3565b6001600f60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550505050505050565b600061130b83612fae565b82106113505782826040517f374f8b4f0000000000000000000000000000000000000000000000000000000081526004016113479291906144dc565b60405180910390fd5b600080600190505b6000548110156113e25761136b81612a50565b80156113aa575061137b81612a6f565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b156113cf578184036113c05780925050506113e5565b81806113cb90614505565b9250505b80806113da90614505565b915050611358565b50505b92915050565b60116020528060005260406000206000915090505481565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156115d3573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036114755761147084848461310b565b6115df565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b81526004016114be9291906141fb565b602060405180830381865afa1580156114db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ff9190614239565b801561159157506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b815260040161154f9291906141fb565b602060405180830381865afa15801561156c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115909190614239565b5b6115d257336040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016115c99190613a4d565b60405180910390fd5b5b6115de84848461310b565b5b50505050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614611653576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161164a906142b2565b60405180910390fd5b600180600381111561166857611667613e95565b5b601060009054906101000a900460ff16600381111561168a57611689613e95565b5b146116ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116c19061431e565b60405180910390fd5b6000801b600d5403611708576040517f93dff14200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000339050600e60008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561179c57806040517f6acdb0950000000000000000000000000000000000000000000000000000000081526004016117939190613a4d565b60405180910390fd5b6000816040516020016117af9190614386565b6040516020818303038152906040528051906020012090506000600d546117d68684612d9d565b1490508061181b57826040517f186a628d0000000000000000000000000000000000000000000000000000000081526004016118129190613a4d565b60405180910390fd5b6000611825610dcb565b9050600c54600a548261183891906143d0565b1115611879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161187090614450565b60405180910390fd5b60085434146118bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118b4906144bc565b60405180910390fd5b6118c933600a54612df3565b6001600e60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550505050505050565b6000611933611ce7565b821061197657816040517f125c19b000000000000000000000000000000000000000000000000000000000815260040161196d9190613ae3565b60405180910390fd5b60018261198391906143d0565b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166119ae611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614611a0657806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016119fd9190613a4d565b60405180910390fd5b611a0f8261312b565b5050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611a37611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614611a8f57806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401611a869190613a4d565b60405180910390fd5b81601060006101000a81548160ff02191690836003811115611ab457611ab3613e95565b5b02179055505050565b601060009054906101000a900460ff1681565b600081611adc81612a50565b611b1d57806040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600401611b149190613ae3565b60405180910390fd5b611b2683612a6f565b915050919050565b600a5481565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611b58611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614611bb057806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401611ba79190613a4d565b60405180910390fd5b6000611bba610dcb565b9050808311611bfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bf5906145bf565b60405180910390fd5b600c548310611c42576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c3990614651565b60405180910390fd5b82600c81905550505050565b6000611c5982612fae565b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611c84611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614611cdc57806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401611cd39190613a4d565b60405180910390fd5b816008819055505050565b60006001600054611cf89190614671565b905090565b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60028054611d3490614193565b80601f0160208091040260200160405190810160405280929190818152602001828054611d6090614193565b8015611dad5780601f10611d8257610100808354040283529160200191611dad565b820191906000526020600020905b815481529060010190602001808311611d9057829003601f168201915b505050505081565b60003390508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611e2a57826040517ff2b21e1c000000000000000000000000000000000000000000000000000000008152600401611e219190613a4d565b60405180910390fd5b81600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3184604051611f1b91906138dc565b60405180910390a3505050565b60095481565b8360006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156120ff573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611fa157611f9c8585858561313e565b61210c565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401611fea9291906141fb565b602060405180830381865afa158015612007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202b9190614239565b80156120bd57506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b815260040161207b9291906141fb565b602060405180830381865afa158015612098573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bc9190614239565b5b6120fe57336040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016120f59190613a4d565b60405180910390fd5b5b61210b8585858561313e565b5b5050505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16612137611cfd565b73ffffffffffffffffffffffffffffffffffffffff161461218f57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016121869190613a4d565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146121fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121f4906142b2565b60405180910390fd5b6000612207610dcb565b9050600c54848261221891906143d0565b1115612259576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225090614450565b60405180910390fd5b6122638385612df3565b50505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661228d611cfd565b73ffffffffffffffffffffffffffffffffffffffff16146122e557806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016122dc9190613a4d565b60405180910390fd5b816009819055505050565b6060816122fc81612a50565b61233d57806040517f1cf4d9a40000000000000000000000000000000000000000000000000000000081526004016123349190613ae3565b60405180910390fd5b60006006805461234c90614193565b9050116123615761235c8361319c565b61238d565b600661236c8461319c565b60405160200161237d929190614779565b6040516020818303038152906040525b915050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166123b9611cfd565b73ffffffffffffffffffffffffffffffffffffffff161461241157806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016124089190613a4d565b60405180910390fd5b81600a819055505050565b600b5481565b600c5481565b600061243483836132fc565b905092915050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146124aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124a1906142b2565b60405180910390fd5b60038060038111156124bf576124be613e95565b5b601060009054906101000a900460ff1660038111156124e1576124e0613e95565b5b14612521576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125189061431e565b60405180910390fd5b600061252b610dcb565b9050600b5483601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461257b91906143d0565b11156125bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125b3906147e9565b60405180910390fd5b600c5483826125cb91906143d0565b111561260c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161260390614450565b60405180910390fd5b6009548361261a9190614809565b341461265b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612652906144bc565b60405180910390fd5b6126653384612df3565b82601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546126b491906143d0565b92505081905550505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166126e4611cfd565b73ffffffffffffffffffffffffffffffffffffffff161461273c57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016127339190613a4d565b60405180910390fd5b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905082600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16612827611cfd565b73ffffffffffffffffffffffffffffffffffffffff161461287f57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016128769190613a4d565b60405180910390fd5b6000479050600081116128c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128be90614897565b60405180910390fd5b8083111561290a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161290190614903565b60405180910390fd5b600084905060008173ffffffffffffffffffffffffffffffffffffffff168560405161293590614954565b60006040518083038185875af1925050503d8060008114612972576040519150601f19603f3d011682016040523d82523d6000602084013e612977565b606091505b50509050806129bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129b2906149b5565b60405180910390fd5b505050505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166129e7611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614612a3f57806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401612a369190613a4d565b60405180910390fd5b81600d819055505050565b60085481565b6000808203612a625760009050612a6a565b600054821090505b919050565b60008082905060006005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612b2b578180612aed906149d5565b9250506005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050612aae565b8092505050919050565b6000808473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480612bd057506003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b80612be15750612be085856132fc565b5b9050809150509392505050565b6000612bf8611ce7565b905090565b80612c0781612a50565b612c4857806040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600401612c3f9190613ae3565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612cae576040517f14242cb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003390506000612cbe84612a6f565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614612d34578086856040517fe02b28e7000000000000000000000000000000000000000000000000000000008152600401612d2b939291906141c4565b60405180910390fd5b6000612d41828487612b35565b905080612d89578183866040517f19f48dff000000000000000000000000000000000000000000000000000000008152600401612d80939291906141c4565b60405180910390fd5b612d94828787613390565b50505050505050565b60008082905060005b8451811015612de857612dd382868381518110612dc657612dc56149fe565b5b6020026020010151613678565b91508080612de090614505565b915050612da6565b508091505092915050565b60008054905060008282612e0791906143d0565b90506000600182612e189190614671565b9050846005600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082811115612ec757846005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b81600081905550612eea60008685604051806020016040528060008152506136a3565b612f2b57846040517f015be56a000000000000000000000000000000000000000000000000000000008152600401612f229190613a4d565b60405180910390fd5b60008390505b82811015612fa657808673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a480612f9f90614505565b9050612f31565b505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612fec5760009050613106565b60008080600190505b6000548110156130ff5761300881612a50565b156130ee57600073ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146130ab576005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b8173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036130ed5782806130e990614505565b9350505b5b806130f890614505565b9050612ff5565b5081925050505b919050565b61312683838360405180602001604052806000815250611f2e565b505050565b806006908161313a9190614bc4565b5050565b613149848484610dda565b613155848484846136a3565b61319657826040517f015be56a00000000000000000000000000000000000000000000000000000000815260040161318d9190613a4d565b60405180910390fd5b50505050565b6060600082036131e3576040518060400160405280600181526020017f300000000000000000000000000000000000000000000000000000000000000081525090506132f7565b600082905060005b600082146132155780806131fe90614505565b915050600a8261320e9190614cc5565b91506131eb565b60008167ffffffffffffffff81111561323157613230613b56565b5b6040519080825280601f01601f1916602001820160405280156132635781602001600182028036833780820191505090505b5090505b600085146132f05760018261327c9190614671565b9150600a8561328b9190614cf6565b603061329791906143d0565b60f81b8183815181106132ad576132ac6149fe565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a856132e99190614cc5565b9450613267565b8093505050505b919050565b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60006003600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600182116133f4576001613402565b6001826134019190614671565b5b9050600060018361341391906143d0565b90506000838310801561342b575061342a83612a50565b5b80156134965750600073ffffffffffffffffffffffffffffffffffffffff166005600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b905060006134a383612a50565b801561350e5750600073ffffffffffffffffffffffffffffffffffffffff166005600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b9050811561356957866005600086815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b80156135c257866005600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b856005600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050505050565b60008183106136905761368b8284613811565b61369b565b61369a8383613811565b5b905092915050565b600080843b90506000811115613803578473ffffffffffffffffffffffffffffffffffffffff1663150b7a02338887876040518563ffffffff1660e01b81526004016136f29493929190614d7c565b6020604051808303816000875af192505050801561372e57506040513d601f19601f8201168201806040525081019061372b9190614ddd565b60015b6137b2573d806000811461375e576040519150601f19603f3d011682016040523d82523d6000602084013e613763565b606091505b5060008151036137aa57856040517f015be56a0000000000000000000000000000000000000000000000000000000081526004016137a19190613a4d565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161492505050613809565b60019150505b949350505050565b600082600052816020526040600020905092915050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6138718161383c565b811461387c57600080fd5b50565b60008135905061388e81613868565b92915050565b6000602082840312156138aa576138a9613832565b5b60006138b88482850161387f565b91505092915050565b60008115159050919050565b6138d6816138c1565b82525050565b60006020820190506138f160008301846138cd565b92915050565b6000819050919050565b61390a816138f7565b811461391557600080fd5b50565b60008135905061392781613901565b92915050565b60006020828403121561394357613942613832565b5b600061395184828501613918565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613994578082015181840152602081019050613979565b60008484015250505050565b6000601f19601f8301169050919050565b60006139bc8261395a565b6139c68185613965565b93506139d6818560208601613976565b6139df816139a0565b840191505092915050565b60006020820190508181036000830152613a0481846139b1565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613a3782613a0c565b9050919050565b613a4781613a2c565b82525050565b6000602082019050613a626000830184613a3e565b92915050565b613a7181613a2c565b8114613a7c57600080fd5b50565b600081359050613a8e81613a68565b92915050565b60008060408385031215613aab57613aaa613832565b5b6000613ab985828601613a7f565b9250506020613aca85828601613918565b9150509250929050565b613add816138f7565b82525050565b6000602082019050613af86000830184613ad4565b92915050565b600080600060608486031215613b1757613b16613832565b5b6000613b2586828701613a7f565b9350506020613b3686828701613a7f565b9250506040613b4786828701613918565b9150509250925092565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613b8e826139a0565b810181811067ffffffffffffffff82111715613bad57613bac613b56565b5b80604052505050565b6000613bc0613828565b9050613bcc8282613b85565b919050565b600067ffffffffffffffff821115613bec57613beb613b56565b5b602082029050602081019050919050565b600080fd5b6000819050919050565b613c1581613c02565b8114613c2057600080fd5b50565b600081359050613c3281613c0c565b92915050565b6000613c4b613c4684613bd1565b613bb6565b90508083825260208201905060208402830185811115613c6e57613c6d613bfd565b5b835b81811015613c975780613c838882613c23565b845260208401935050602081019050613c70565b5050509392505050565b600082601f830112613cb657613cb5613b51565b5b8135613cc6848260208601613c38565b91505092915050565b600060208284031215613ce557613ce4613832565b5b600082013567ffffffffffffffff811115613d0357613d02613837565b5b613d0f84828501613ca1565b91505092915050565b600060208284031215613d2e57613d2d613832565b5b6000613d3c84828501613a7f565b91505092915050565b600080fd5b600067ffffffffffffffff821115613d6557613d64613b56565b5b613d6e826139a0565b9050602081019050919050565b82818337600083830152505050565b6000613d9d613d9884613d4a565b613bb6565b905082815260208101848484011115613db957613db8613d45565b5b613dc4848285613d7b565b509392505050565b600082601f830112613de157613de0613b51565b5b8135613df1848260208601613d8a565b91505092915050565b600060208284031215613e1057613e0f613832565b5b600082013567ffffffffffffffff811115613e2e57613e2d613837565b5b613e3a84828501613dcc565b91505092915050565b60048110613e5057600080fd5b50565b600081359050613e6281613e43565b92915050565b600060208284031215613e7e57613e7d613832565b5b6000613e8c84828501613e53565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110613ed557613ed4613e95565b5b50565b6000819050613ee682613ec4565b919050565b6000613ef682613ed8565b9050919050565b613f0681613eeb565b82525050565b6000602082019050613f216000830184613efd565b92915050565b613f30816138c1565b8114613f3b57600080fd5b50565b600081359050613f4d81613f27565b92915050565b60008060408385031215613f6a57613f69613832565b5b6000613f7885828601613a7f565b9250506020613f8985828601613f3e565b9150509250929050565b600067ffffffffffffffff821115613fae57613fad613b56565b5b613fb7826139a0565b9050602081019050919050565b6000613fd7613fd284613f93565b613bb6565b905082815260208101848484011115613ff357613ff2613d45565b5b613ffe848285613d7b565b509392505050565b600082601f83011261401b5761401a613b51565b5b813561402b848260208601613fc4565b91505092915050565b6000806000806080858703121561404e5761404d613832565b5b600061405c87828801613a7f565b945050602061406d87828801613a7f565b935050604061407e87828801613918565b925050606085013567ffffffffffffffff81111561409f5761409e613837565b5b6140ab87828801614006565b91505092959194509250565b600080604083850312156140ce576140cd613832565b5b60006140dc85828601613918565b92505060206140ed85828601613a7f565b9150509250929050565b6000806040838503121561410e5761410d613832565b5b600061411c85828601613a7f565b925050602061412d85828601613a7f565b9150509250929050565b60006020828403121561414d5761414c613832565b5b600061415b84828501613c23565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806141ab57607f821691505b6020821081036141be576141bd614164565b5b50919050565b60006060820190506141d96000830186613a3e565b6141e66020830185613a3e565b6141f36040830184613ad4565b949350505050565b60006040820190506142106000830185613a3e565b61421d6020830184613a3e565b9392505050565b60008151905061423381613f27565b92915050565b60006020828403121561424f5761424e613832565b5b600061425d84828501614224565b91505092915050565b7f4e6f20736d61727420636f6e7472616374732061726520616c6c6f7765640000600082015250565b600061429c601e83613965565b91506142a782614266565b602082019050919050565b600060208201905081810360008301526142cb8161428f565b9050919050565b7f53616c65206e6f74206163746976650000000000000000000000000000000000600082015250565b6000614308600f83613965565b9150614313826142d2565b602082019050919050565b60006020820190508181036000830152614337816142fb565b9050919050565b60008160601b9050919050565b60006143568261433e565b9050919050565b60006143688261434b565b9050919050565b61438061437b82613a2c565b61435d565b82525050565b6000614392828461436f565b60148201915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006143db826138f7565b91506143e6836138f7565b92508282019050808211156143fe576143fd6143a1565b5b92915050565b7f4578636565647320737570706c79000000000000000000000000000000000000600082015250565b600061443a600e83613965565b915061444582614404565b602082019050919050565b600060208201905081810360008301526144698161442d565b9050919050565b7f45746865722073656e74206973206e6f7420636f727265637400000000000000600082015250565b60006144a6601983613965565b91506144b182614470565b602082019050919050565b600060208201905081810360008301526144d581614499565b9050919050565b60006040820190506144f16000830185613a3e565b6144fe6020830184613ad4565b9392505050565b6000614510826138f7565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614542576145416143a1565b5b600182019050919050565b7f4d617820737570706c792073686f756c6420626520677265617465722074686160008201527f6e2063757272656e7420737570706c7900000000000000000000000000000000602082015250565b60006145a9603083613965565b91506145b48261454d565b604082019050919050565b600060208201905081810360008301526145d88161459c565b9050919050565b7f4d617820737570706c792073686f756c6420626520677265617465722074686160008201527f6e2070726576696f7573206d617820737570706c790000000000000000000000602082015250565b600061463b603583613965565b9150614646826145df565b604082019050919050565b6000602082019050818103600083015261466a8161462e565b9050919050565b600061467c826138f7565b9150614687836138f7565b925082820390508181111561469f5761469e6143a1565b5b92915050565b600081905092915050565b60008190508160005260206000209050919050565b600081546146d281614193565b6146dc81866146a5565b945060018216600081146146f7576001811461470c5761473f565b60ff198316865281151582028601935061473f565b614715856146b0565b60005b8381101561473757815481890152600182019150602081019050614718565b838801955050505b50505092915050565b60006147538261395a565b61475d81856146a5565b935061476d818560208601613976565b80840191505092915050565b600061478582856146c5565b91506147918284614748565b91508190509392505050565b7f45786365656473206d696e74207065722077616c6c6574000000000000000000600082015250565b60006147d3601783613965565b91506147de8261479d565b602082019050919050565b60006020820190508181036000830152614802816147c6565b9050919050565b6000614814826138f7565b915061481f836138f7565b925082820261482d816138f7565b91508282048414831517614844576148436143a1565b5b5092915050565b7f4e6f2062616c616e636520746f20776974686472617700000000000000000000600082015250565b6000614881601683613965565b915061488c8261484b565b602082019050919050565b600060208201905081810360008301526148b081614874565b9050919050565b7f416d6f756e74206973206e6f742076616c696400000000000000000000000000600082015250565b60006148ed601383613965565b91506148f8826148b7565b602082019050919050565b6000602082019050818103600083015261491c816148e0565b9050919050565b600081905092915050565b50565b600061493e600083614923565b91506149498261492e565b600082019050919050565b600061495f82614931565b9150819050919050565b7f5472616e73616374696f6e206661696c65640000000000000000000000000000600082015250565b600061499f601283613965565b91506149aa82614969565b602082019050919050565b600060208201905081810360008301526149ce81614992565b9050919050565b60006149e0826138f7565b9150600082036149f3576149f26143a1565b5b600182039050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020601f8301049050919050565b600082821b905092915050565b600060088302614a7a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614a3d565b614a848683614a3d565b95508019841693508086168417925050509392505050565b6000819050919050565b6000614ac1614abc614ab7846138f7565b614a9c565b6138f7565b9050919050565b6000819050919050565b614adb83614aa6565b614aef614ae782614ac8565b848454614a4a565b825550505050565b600090565b614b04614af7565b614b0f818484614ad2565b505050565b5b81811015614b3357614b28600082614afc565b600181019050614b15565b5050565b601f821115614b7857614b49816146b0565b614b5284614a2d565b81016020851015614b61578190505b614b75614b6d85614a2d565b830182614b14565b50505b505050565b600082821c905092915050565b6000614b9b60001984600802614b7d565b1980831691505092915050565b6000614bb48383614b8a565b9150826002028217905092915050565b614bcd8261395a565b67ffffffffffffffff811115614be657614be5613b56565b5b614bf08254614193565b614bfb828285614b37565b600060209050601f831160018114614c2e5760008415614c1c578287015190505b614c268582614ba8565b865550614c8e565b601f198416614c3c866146b0565b60005b82811015614c6457848901518255600182019150602085019450602081019050614c3f565b86831015614c815784890151614c7d601f891682614b8a565b8355505b6001600288020188555050505b505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614cd0826138f7565b9150614cdb836138f7565b925082614ceb57614cea614c96565b5b828204905092915050565b6000614d01826138f7565b9150614d0c836138f7565b925082614d1c57614d1b614c96565b5b828206905092915050565b600081519050919050565b600082825260208201905092915050565b6000614d4e82614d27565b614d588185614d32565b9350614d68818560208601613976565b614d71816139a0565b840191505092915050565b6000608082019050614d916000830187613a3e565b614d9e6020830186613a3e565b614dab6040830185613ad4565b8181036060830152614dbd8184614d43565b905095945050505050565b600081519050614dd781613868565b92915050565b600060208284031215614df357614df2613832565b5b6000614e0184828501614dc8565b9150509291505056fea2646970667358221220ff14bd865b00fa40770dcc60e989ad61973c8b2b0c621a86db37e1f3ba25422964736f6c63430008110033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000a556e646561644368656600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b554e4445414443484546530000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040697066733a2f2f516d614c484d7162626438594e5934787a4b7458596843506654764b5755794d4d6f72566155347838456f69746e2f70726572657665616c2f

Deployed Bytecode

0x6080604052600436106102305760003560e01c806370a082311161012e578063c87b56dd116100ab578063efd0cbf91161006f578063efd0cbf914610848578063f2fde38b14610864578063f3fef3a31461088d578063f5aa406d146108b6578063fc1a1c36146108df57610230565b8063c87b56dd1461074f578063c95d83c61461078c578063cfe1908d146107b5578063d5abeb01146107e0578063e985e9c51461080b57610230565b8063a22cb465116100f2578063a22cb4651461068d578063a945bf80146106b6578063b88d4fde146106e1578063bc63f02e1461070a578063c62752551461072657610230565b806370a08231146105a6578063717d57d3146105e35780637e9845f51461060c5780638da5cb5b1461063757806395d89b411461066257610230565b80633a602b4d116101bc5780635a67de07116101805780635a67de07146104c1578063603f4d52146104ea5780636352211e1461051557806366cc5f0d146105525780636f8b44b01461057d57610230565b80633a602b4d146103d957806342842e0e1461041657806344d843811461043f5780634f6ccce71461045b57806355f804b31461049857610230565b8063095ea7b311610203578063095ea7b31461030357806318160ddd1461032c57806323b872dd1461035757806328bb1a2e146103805780632f745c591461039c57610230565b806301ffc9a71461023557806302c366bc1461027257806306fdde031461029b578063081812fc146102c6575b600080fd5b34801561024157600080fd5b5061025c60048036038101906102579190613894565b61090a565b60405161026991906138dc565b60405180910390f35b34801561027e57600080fd5b506102996004803603810190610294919061392d565b610aac565b005b3480156102a757600080fd5b506102b0610b33565b6040516102bd91906139ea565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e8919061392d565b610bc1565b6040516102fa9190613a4d565b60405180910390f35b34801561030f57600080fd5b5061032a60048036038101906103259190613a94565b610bf4565b005b34801561033857600080fd5b50610341610dcb565b60405161034e9190613ae3565b60405180910390f35b34801561036357600080fd5b5061037e60048036038101906103799190613afe565b610dda565b005b61039a60048036038101906103959190613ccf565b610fbc565b005b3480156103a857600080fd5b506103c360048036038101906103be9190613a94565b611300565b6040516103d09190613ae3565b60405180910390f35b3480156103e557600080fd5b5061040060048036038101906103fb9190613d18565b6113eb565b60405161040d9190613ae3565b60405180910390f35b34801561042257600080fd5b5061043d60048036038101906104389190613afe565b611403565b005b61045960048036038101906104549190613ccf565b6115e5565b005b34801561046757600080fd5b50610482600480360381019061047d919061392d565b611929565b60405161048f9190613ae3565b60405180910390f35b3480156104a457600080fd5b506104bf60048036038101906104ba9190613dfa565b61198a565b005b3480156104cd57600080fd5b506104e860048036038101906104e39190613e68565b611a13565b005b3480156104f657600080fd5b506104ff611abd565b60405161050c9190613f0c565b60405180910390f35b34801561052157600080fd5b5061053c6004803603810190610537919061392d565b611ad0565b6040516105499190613a4d565b60405180910390f35b34801561055e57600080fd5b50610567611b2e565b6040516105749190613ae3565b60405180910390f35b34801561058957600080fd5b506105a4600480360381019061059f919061392d565b611b34565b005b3480156105b257600080fd5b506105cd60048036038101906105c89190613d18565b611c4e565b6040516105da9190613ae3565b60405180910390f35b3480156105ef57600080fd5b5061060a6004803603810190610605919061392d565b611c60565b005b34801561061857600080fd5b50610621611ce7565b60405161062e9190613ae3565b60405180910390f35b34801561064357600080fd5b5061064c611cfd565b6040516106599190613a4d565b60405180910390f35b34801561066e57600080fd5b50610677611d27565b60405161068491906139ea565b60405180910390f35b34801561069957600080fd5b506106b460048036038101906106af9190613f53565b611db5565b005b3480156106c257600080fd5b506106cb611f28565b6040516106d89190613ae3565b60405180910390f35b3480156106ed57600080fd5b5061070860048036038101906107039190614034565b611f2e565b005b610724600480360381019061071f91906140b7565b612113565b005b34801561073257600080fd5b5061074d6004803603810190610748919061392d565b612269565b005b34801561075b57600080fd5b506107766004803603810190610771919061392d565b6122f0565b60405161078391906139ea565b60405180910390f35b34801561079857600080fd5b506107b360048036038101906107ae919061392d565b612395565b005b3480156107c157600080fd5b506107ca61241c565b6040516107d79190613ae3565b60405180910390f35b3480156107ec57600080fd5b506107f5612422565b6040516108029190613ae3565b60405180910390f35b34801561081757600080fd5b50610832600480360381019061082d91906140f7565b612428565b60405161083f91906138dc565b60405180910390f35b610862600480360381019061085d919061392d565b61243c565b005b34801561087057600080fd5b5061088b60048036038101906108869190613d18565b6126c0565b005b34801561089957600080fd5b506108b460048036038101906108af9190613a94565b612803565b005b3480156108c257600080fd5b506108dd60048036038101906108d89190614137565b6129c3565b005b3480156108eb57600080fd5b506108f4612a4a565b6040516109019190613ae3565b60405180910390f35b60007f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806109d557507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a3d57507f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610aa557507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16610ad0611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614610b2857806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401610b1f9190613a4d565b60405180910390fd5b81600b819055505050565b60018054610b4090614193565b80601f0160208091040260200160405190810160405280929190818152602001828054610b6c90614193565b8015610bb95780601f10610b8e57610100808354040283529160200191610bb9565b820191906000526020600020905b815481529060010190602001808311610b9c57829003601f168201915b505050505081565b60036020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b80610bfe81612a50565b610c3f57806040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600401610c369190613ae3565b60405180910390fd5b60003390506000610c4f84612a6f565b90508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610cc157846040517ff2b21e1c000000000000000000000000000000000000000000000000000000008152600401610cb89190613a4d565b60405180910390fd5b6000610cce828487612b35565b905080610d16578183866040517f19f48dff000000000000000000000000000000000000000000000000000000008152600401610d0d939291906141c4565b60405180910390fd5b856003600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050505050565b6000610dd5612bee565b905090565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115610faa573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e4c57610e47848484612bfd565b610fb6565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401610e959291906141fb565b602060405180830381865afa158015610eb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed69190614239565b8015610f6857506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401610f269291906141fb565b602060405180830381865afa158015610f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190614239565b5b610fa957336040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401610fa09190613a4d565b60405180910390fd5b5b610fb5848484612bfd565b5b50505050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff161461102a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611021906142b2565b60405180910390fd5b600280600381111561103f5761103e613e95565b5b601060009054906101000a900460ff16600381111561106157611060613e95565b5b146110a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110989061431e565b60405180910390fd5b6000801b600d54036110df576040517f93dff14200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000339050600f60008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561117357806040517f6acdb09500000000000000000000000000000000000000000000000000000000815260040161116a9190613a4d565b60405180910390fd5b6000816040516020016111869190614386565b6040516020818303038152906040528051906020012090506000600d546111ad8684612d9d565b149050806111f257826040517f186a628d0000000000000000000000000000000000000000000000000000000081526004016111e99190613a4d565b60405180910390fd5b60006111fc610dcb565b9050600c54600a548261120f91906143d0565b1115611250576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124790614450565b60405180910390fd5b6008543414611294576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128b906144bc565b60405180910390fd5b6112a033600a54612df3565b6001600f60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550505050505050565b600061130b83612fae565b82106113505782826040517f374f8b4f0000000000000000000000000000000000000000000000000000000081526004016113479291906144dc565b60405180910390fd5b600080600190505b6000548110156113e25761136b81612a50565b80156113aa575061137b81612a6f565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b156113cf578184036113c05780925050506113e5565b81806113cb90614505565b9250505b80806113da90614505565b915050611358565b50505b92915050565b60116020528060005260406000206000915090505481565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156115d3573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036114755761147084848461310b565b6115df565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b81526004016114be9291906141fb565b602060405180830381865afa1580156114db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ff9190614239565b801561159157506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b815260040161154f9291906141fb565b602060405180830381865afa15801561156c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115909190614239565b5b6115d257336040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016115c99190613a4d565b60405180910390fd5b5b6115de84848461310b565b5b50505050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614611653576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161164a906142b2565b60405180910390fd5b600180600381111561166857611667613e95565b5b601060009054906101000a900460ff16600381111561168a57611689613e95565b5b146116ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116c19061431e565b60405180910390fd5b6000801b600d5403611708576040517f93dff14200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000339050600e60008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561179c57806040517f6acdb0950000000000000000000000000000000000000000000000000000000081526004016117939190613a4d565b60405180910390fd5b6000816040516020016117af9190614386565b6040516020818303038152906040528051906020012090506000600d546117d68684612d9d565b1490508061181b57826040517f186a628d0000000000000000000000000000000000000000000000000000000081526004016118129190613a4d565b60405180910390fd5b6000611825610dcb565b9050600c54600a548261183891906143d0565b1115611879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161187090614450565b60405180910390fd5b60085434146118bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118b4906144bc565b60405180910390fd5b6118c933600a54612df3565b6001600e60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550505050505050565b6000611933611ce7565b821061197657816040517f125c19b000000000000000000000000000000000000000000000000000000000815260040161196d9190613ae3565b60405180910390fd5b60018261198391906143d0565b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166119ae611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614611a0657806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016119fd9190613a4d565b60405180910390fd5b611a0f8261312b565b5050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611a37611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614611a8f57806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401611a869190613a4d565b60405180910390fd5b81601060006101000a81548160ff02191690836003811115611ab457611ab3613e95565b5b02179055505050565b601060009054906101000a900460ff1681565b600081611adc81612a50565b611b1d57806040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600401611b149190613ae3565b60405180910390fd5b611b2683612a6f565b915050919050565b600a5481565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611b58611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614611bb057806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401611ba79190613a4d565b60405180910390fd5b6000611bba610dcb565b9050808311611bfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bf5906145bf565b60405180910390fd5b600c548310611c42576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c3990614651565b60405180910390fd5b82600c81905550505050565b6000611c5982612fae565b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611c84611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614611cdc57806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401611cd39190613a4d565b60405180910390fd5b816008819055505050565b60006001600054611cf89190614671565b905090565b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60028054611d3490614193565b80601f0160208091040260200160405190810160405280929190818152602001828054611d6090614193565b8015611dad5780601f10611d8257610100808354040283529160200191611dad565b820191906000526020600020905b815481529060010190602001808311611d9057829003601f168201915b505050505081565b60003390508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611e2a57826040517ff2b21e1c000000000000000000000000000000000000000000000000000000008152600401611e219190613a4d565b60405180910390fd5b81600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3184604051611f1b91906138dc565b60405180910390a3505050565b60095481565b8360006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156120ff573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611fa157611f9c8585858561313e565b61210c565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401611fea9291906141fb565b602060405180830381865afa158015612007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202b9190614239565b80156120bd57506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b815260040161207b9291906141fb565b602060405180830381865afa158015612098573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bc9190614239565b5b6120fe57336040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016120f59190613a4d565b60405180910390fd5b5b61210b8585858561313e565b5b5050505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16612137611cfd565b73ffffffffffffffffffffffffffffffffffffffff161461218f57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016121869190613a4d565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146121fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121f4906142b2565b60405180910390fd5b6000612207610dcb565b9050600c54848261221891906143d0565b1115612259576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225090614450565b60405180910390fd5b6122638385612df3565b50505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661228d611cfd565b73ffffffffffffffffffffffffffffffffffffffff16146122e557806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016122dc9190613a4d565b60405180910390fd5b816009819055505050565b6060816122fc81612a50565b61233d57806040517f1cf4d9a40000000000000000000000000000000000000000000000000000000081526004016123349190613ae3565b60405180910390fd5b60006006805461234c90614193565b9050116123615761235c8361319c565b61238d565b600661236c8461319c565b60405160200161237d929190614779565b6040516020818303038152906040525b915050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166123b9611cfd565b73ffffffffffffffffffffffffffffffffffffffff161461241157806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016124089190613a4d565b60405180910390fd5b81600a819055505050565b600b5481565b600c5481565b600061243483836132fc565b905092915050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146124aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124a1906142b2565b60405180910390fd5b60038060038111156124bf576124be613e95565b5b601060009054906101000a900460ff1660038111156124e1576124e0613e95565b5b14612521576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125189061431e565b60405180910390fd5b600061252b610dcb565b9050600b5483601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461257b91906143d0565b11156125bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125b3906147e9565b60405180910390fd5b600c5483826125cb91906143d0565b111561260c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161260390614450565b60405180910390fd5b6009548361261a9190614809565b341461265b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612652906144bc565b60405180910390fd5b6126653384612df3565b82601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546126b491906143d0565b92505081905550505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166126e4611cfd565b73ffffffffffffffffffffffffffffffffffffffff161461273c57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016127339190613a4d565b60405180910390fd5b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905082600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16612827611cfd565b73ffffffffffffffffffffffffffffffffffffffff161461287f57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016128769190613a4d565b60405180910390fd5b6000479050600081116128c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128be90614897565b60405180910390fd5b8083111561290a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161290190614903565b60405180910390fd5b600084905060008173ffffffffffffffffffffffffffffffffffffffff168560405161293590614954565b60006040518083038185875af1925050503d8060008114612972576040519150601f19603f3d011682016040523d82523d6000602084013e612977565b606091505b50509050806129bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129b2906149b5565b60405180910390fd5b505050505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166129e7611cfd565b73ffffffffffffffffffffffffffffffffffffffff1614612a3f57806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401612a369190613a4d565b60405180910390fd5b81600d819055505050565b60085481565b6000808203612a625760009050612a6a565b600054821090505b919050565b60008082905060006005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612b2b578180612aed906149d5565b9250506005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050612aae565b8092505050919050565b6000808473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480612bd057506003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b80612be15750612be085856132fc565b5b9050809150509392505050565b6000612bf8611ce7565b905090565b80612c0781612a50565b612c4857806040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600401612c3f9190613ae3565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612cae576040517f14242cb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003390506000612cbe84612a6f565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614612d34578086856040517fe02b28e7000000000000000000000000000000000000000000000000000000008152600401612d2b939291906141c4565b60405180910390fd5b6000612d41828487612b35565b905080612d89578183866040517f19f48dff000000000000000000000000000000000000000000000000000000008152600401612d80939291906141c4565b60405180910390fd5b612d94828787613390565b50505050505050565b60008082905060005b8451811015612de857612dd382868381518110612dc657612dc56149fe565b5b6020026020010151613678565b91508080612de090614505565b915050612da6565b508091505092915050565b60008054905060008282612e0791906143d0565b90506000600182612e189190614671565b9050846005600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082811115612ec757846005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b81600081905550612eea60008685604051806020016040528060008152506136a3565b612f2b57846040517f015be56a000000000000000000000000000000000000000000000000000000008152600401612f229190613a4d565b60405180910390fd5b60008390505b82811015612fa657808673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a480612f9f90614505565b9050612f31565b505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612fec5760009050613106565b60008080600190505b6000548110156130ff5761300881612a50565b156130ee57600073ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146130ab576005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b8173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036130ed5782806130e990614505565b9350505b5b806130f890614505565b9050612ff5565b5081925050505b919050565b61312683838360405180602001604052806000815250611f2e565b505050565b806006908161313a9190614bc4565b5050565b613149848484610dda565b613155848484846136a3565b61319657826040517f015be56a00000000000000000000000000000000000000000000000000000000815260040161318d9190613a4d565b60405180910390fd5b50505050565b6060600082036131e3576040518060400160405280600181526020017f300000000000000000000000000000000000000000000000000000000000000081525090506132f7565b600082905060005b600082146132155780806131fe90614505565b915050600a8261320e9190614cc5565b91506131eb565b60008167ffffffffffffffff81111561323157613230613b56565b5b6040519080825280601f01601f1916602001820160405280156132635781602001600182028036833780820191505090505b5090505b600085146132f05760018261327c9190614671565b9150600a8561328b9190614cf6565b603061329791906143d0565b60f81b8183815181106132ad576132ac6149fe565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a856132e99190614cc5565b9450613267565b8093505050505b919050565b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60006003600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600182116133f4576001613402565b6001826134019190614671565b5b9050600060018361341391906143d0565b90506000838310801561342b575061342a83612a50565b5b80156134965750600073ffffffffffffffffffffffffffffffffffffffff166005600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b905060006134a383612a50565b801561350e5750600073ffffffffffffffffffffffffffffffffffffffff166005600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b9050811561356957866005600086815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b80156135c257866005600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b856005600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050505050565b60008183106136905761368b8284613811565b61369b565b61369a8383613811565b5b905092915050565b600080843b90506000811115613803578473ffffffffffffffffffffffffffffffffffffffff1663150b7a02338887876040518563ffffffff1660e01b81526004016136f29493929190614d7c565b6020604051808303816000875af192505050801561372e57506040513d601f19601f8201168201806040525081019061372b9190614ddd565b60015b6137b2573d806000811461375e576040519150601f19603f3d011682016040523d82523d6000602084013e613763565b606091505b5060008151036137aa57856040517f015be56a0000000000000000000000000000000000000000000000000000000081526004016137a19190613a4d565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161492505050613809565b60019150505b949350505050565b600082600052816020526040600020905092915050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6138718161383c565b811461387c57600080fd5b50565b60008135905061388e81613868565b92915050565b6000602082840312156138aa576138a9613832565b5b60006138b88482850161387f565b91505092915050565b60008115159050919050565b6138d6816138c1565b82525050565b60006020820190506138f160008301846138cd565b92915050565b6000819050919050565b61390a816138f7565b811461391557600080fd5b50565b60008135905061392781613901565b92915050565b60006020828403121561394357613942613832565b5b600061395184828501613918565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613994578082015181840152602081019050613979565b60008484015250505050565b6000601f19601f8301169050919050565b60006139bc8261395a565b6139c68185613965565b93506139d6818560208601613976565b6139df816139a0565b840191505092915050565b60006020820190508181036000830152613a0481846139b1565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613a3782613a0c565b9050919050565b613a4781613a2c565b82525050565b6000602082019050613a626000830184613a3e565b92915050565b613a7181613a2c565b8114613a7c57600080fd5b50565b600081359050613a8e81613a68565b92915050565b60008060408385031215613aab57613aaa613832565b5b6000613ab985828601613a7f565b9250506020613aca85828601613918565b9150509250929050565b613add816138f7565b82525050565b6000602082019050613af86000830184613ad4565b92915050565b600080600060608486031215613b1757613b16613832565b5b6000613b2586828701613a7f565b9350506020613b3686828701613a7f565b9250506040613b4786828701613918565b9150509250925092565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613b8e826139a0565b810181811067ffffffffffffffff82111715613bad57613bac613b56565b5b80604052505050565b6000613bc0613828565b9050613bcc8282613b85565b919050565b600067ffffffffffffffff821115613bec57613beb613b56565b5b602082029050602081019050919050565b600080fd5b6000819050919050565b613c1581613c02565b8114613c2057600080fd5b50565b600081359050613c3281613c0c565b92915050565b6000613c4b613c4684613bd1565b613bb6565b90508083825260208201905060208402830185811115613c6e57613c6d613bfd565b5b835b81811015613c975780613c838882613c23565b845260208401935050602081019050613c70565b5050509392505050565b600082601f830112613cb657613cb5613b51565b5b8135613cc6848260208601613c38565b91505092915050565b600060208284031215613ce557613ce4613832565b5b600082013567ffffffffffffffff811115613d0357613d02613837565b5b613d0f84828501613ca1565b91505092915050565b600060208284031215613d2e57613d2d613832565b5b6000613d3c84828501613a7f565b91505092915050565b600080fd5b600067ffffffffffffffff821115613d6557613d64613b56565b5b613d6e826139a0565b9050602081019050919050565b82818337600083830152505050565b6000613d9d613d9884613d4a565b613bb6565b905082815260208101848484011115613db957613db8613d45565b5b613dc4848285613d7b565b509392505050565b600082601f830112613de157613de0613b51565b5b8135613df1848260208601613d8a565b91505092915050565b600060208284031215613e1057613e0f613832565b5b600082013567ffffffffffffffff811115613e2e57613e2d613837565b5b613e3a84828501613dcc565b91505092915050565b60048110613e5057600080fd5b50565b600081359050613e6281613e43565b92915050565b600060208284031215613e7e57613e7d613832565b5b6000613e8c84828501613e53565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110613ed557613ed4613e95565b5b50565b6000819050613ee682613ec4565b919050565b6000613ef682613ed8565b9050919050565b613f0681613eeb565b82525050565b6000602082019050613f216000830184613efd565b92915050565b613f30816138c1565b8114613f3b57600080fd5b50565b600081359050613f4d81613f27565b92915050565b60008060408385031215613f6a57613f69613832565b5b6000613f7885828601613a7f565b9250506020613f8985828601613f3e565b9150509250929050565b600067ffffffffffffffff821115613fae57613fad613b56565b5b613fb7826139a0565b9050602081019050919050565b6000613fd7613fd284613f93565b613bb6565b905082815260208101848484011115613ff357613ff2613d45565b5b613ffe848285613d7b565b509392505050565b600082601f83011261401b5761401a613b51565b5b813561402b848260208601613fc4565b91505092915050565b6000806000806080858703121561404e5761404d613832565b5b600061405c87828801613a7f565b945050602061406d87828801613a7f565b935050604061407e87828801613918565b925050606085013567ffffffffffffffff81111561409f5761409e613837565b5b6140ab87828801614006565b91505092959194509250565b600080604083850312156140ce576140cd613832565b5b60006140dc85828601613918565b92505060206140ed85828601613a7f565b9150509250929050565b6000806040838503121561410e5761410d613832565b5b600061411c85828601613a7f565b925050602061412d85828601613a7f565b9150509250929050565b60006020828403121561414d5761414c613832565b5b600061415b84828501613c23565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806141ab57607f821691505b6020821081036141be576141bd614164565b5b50919050565b60006060820190506141d96000830186613a3e565b6141e66020830185613a3e565b6141f36040830184613ad4565b949350505050565b60006040820190506142106000830185613a3e565b61421d6020830184613a3e565b9392505050565b60008151905061423381613f27565b92915050565b60006020828403121561424f5761424e613832565b5b600061425d84828501614224565b91505092915050565b7f4e6f20736d61727420636f6e7472616374732061726520616c6c6f7765640000600082015250565b600061429c601e83613965565b91506142a782614266565b602082019050919050565b600060208201905081810360008301526142cb8161428f565b9050919050565b7f53616c65206e6f74206163746976650000000000000000000000000000000000600082015250565b6000614308600f83613965565b9150614313826142d2565b602082019050919050565b60006020820190508181036000830152614337816142fb565b9050919050565b60008160601b9050919050565b60006143568261433e565b9050919050565b60006143688261434b565b9050919050565b61438061437b82613a2c565b61435d565b82525050565b6000614392828461436f565b60148201915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006143db826138f7565b91506143e6836138f7565b92508282019050808211156143fe576143fd6143a1565b5b92915050565b7f4578636565647320737570706c79000000000000000000000000000000000000600082015250565b600061443a600e83613965565b915061444582614404565b602082019050919050565b600060208201905081810360008301526144698161442d565b9050919050565b7f45746865722073656e74206973206e6f7420636f727265637400000000000000600082015250565b60006144a6601983613965565b91506144b182614470565b602082019050919050565b600060208201905081810360008301526144d581614499565b9050919050565b60006040820190506144f16000830185613a3e565b6144fe6020830184613ad4565b9392505050565b6000614510826138f7565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614542576145416143a1565b5b600182019050919050565b7f4d617820737570706c792073686f756c6420626520677265617465722074686160008201527f6e2063757272656e7420737570706c7900000000000000000000000000000000602082015250565b60006145a9603083613965565b91506145b48261454d565b604082019050919050565b600060208201905081810360008301526145d88161459c565b9050919050565b7f4d617820737570706c792073686f756c6420626520677265617465722074686160008201527f6e2070726576696f7573206d617820737570706c790000000000000000000000602082015250565b600061463b603583613965565b9150614646826145df565b604082019050919050565b6000602082019050818103600083015261466a8161462e565b9050919050565b600061467c826138f7565b9150614687836138f7565b925082820390508181111561469f5761469e6143a1565b5b92915050565b600081905092915050565b60008190508160005260206000209050919050565b600081546146d281614193565b6146dc81866146a5565b945060018216600081146146f7576001811461470c5761473f565b60ff198316865281151582028601935061473f565b614715856146b0565b60005b8381101561473757815481890152600182019150602081019050614718565b838801955050505b50505092915050565b60006147538261395a565b61475d81856146a5565b935061476d818560208601613976565b80840191505092915050565b600061478582856146c5565b91506147918284614748565b91508190509392505050565b7f45786365656473206d696e74207065722077616c6c6574000000000000000000600082015250565b60006147d3601783613965565b91506147de8261479d565b602082019050919050565b60006020820190508181036000830152614802816147c6565b9050919050565b6000614814826138f7565b915061481f836138f7565b925082820261482d816138f7565b91508282048414831517614844576148436143a1565b5b5092915050565b7f4e6f2062616c616e636520746f20776974686472617700000000000000000000600082015250565b6000614881601683613965565b915061488c8261484b565b602082019050919050565b600060208201905081810360008301526148b081614874565b9050919050565b7f416d6f756e74206973206e6f742076616c696400000000000000000000000000600082015250565b60006148ed601383613965565b91506148f8826148b7565b602082019050919050565b6000602082019050818103600083015261491c816148e0565b9050919050565b600081905092915050565b50565b600061493e600083614923565b91506149498261492e565b600082019050919050565b600061495f82614931565b9150819050919050565b7f5472616e73616374696f6e206661696c65640000000000000000000000000000600082015250565b600061499f601283613965565b91506149aa82614969565b602082019050919050565b600060208201905081810360008301526149ce81614992565b9050919050565b60006149e0826138f7565b9150600082036149f3576149f26143a1565b5b600182039050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020601f8301049050919050565b600082821b905092915050565b600060088302614a7a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614a3d565b614a848683614a3d565b95508019841693508086168417925050509392505050565b6000819050919050565b6000614ac1614abc614ab7846138f7565b614a9c565b6138f7565b9050919050565b6000819050919050565b614adb83614aa6565b614aef614ae782614ac8565b848454614a4a565b825550505050565b600090565b614b04614af7565b614b0f818484614ad2565b505050565b5b81811015614b3357614b28600082614afc565b600181019050614b15565b5050565b601f821115614b7857614b49816146b0565b614b5284614a2d565b81016020851015614b61578190505b614b75614b6d85614a2d565b830182614b14565b50505b505050565b600082821c905092915050565b6000614b9b60001984600802614b7d565b1980831691505092915050565b6000614bb48383614b8a565b9150826002028217905092915050565b614bcd8261395a565b67ffffffffffffffff811115614be657614be5613b56565b5b614bf08254614193565b614bfb828285614b37565b600060209050601f831160018114614c2e5760008415614c1c578287015190505b614c268582614ba8565b865550614c8e565b601f198416614c3c866146b0565b60005b82811015614c6457848901518255600182019150602085019450602081019050614c3f565b86831015614c815784890151614c7d601f891682614b8a565b8355505b6001600288020188555050505b505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614cd0826138f7565b9150614cdb836138f7565b925082614ceb57614cea614c96565b5b828204905092915050565b6000614d01826138f7565b9150614d0c836138f7565b925082614d1c57614d1b614c96565b5b828206905092915050565b600081519050919050565b600082825260208201905092915050565b6000614d4e82614d27565b614d588185614d32565b9350614d68818560208601613976565b614d71816139a0565b840191505092915050565b6000608082019050614d916000830187613a3e565b614d9e6020830186613a3e565b614dab6040830185613ad4565b8181036060830152614dbd8184614d43565b905095945050505050565b600081519050614dd781613868565b92915050565b600060208284031215614df357614df2613832565b5b6000614e0184828501614dc8565b9150509291505056fea2646970667358221220ff14bd865b00fa40770dcc60e989ad61973c8b2b0c621a86db37e1f3ba25422964736f6c63430008110033

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

000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000a556e646561644368656600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b554e4445414443484546530000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040697066733a2f2f516d614c484d7162626438594e5934787a4b7458596843506654764b5755794d4d6f72566155347838456f69746e2f70726572657665616c2f

-----Decoded View---------------
Arg [0] : name_ (string): UndeadChef
Arg [1] : symbol_ (string): UNDEADCHEFS
Arg [2] : baseURI_ (string): ipfs://QmaLHMqbbd8YNY4xzKtXYhCPfTvKWUyMMorVaU4x8Eoitn/prereveal/

-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [4] : 556e646561644368656600000000000000000000000000000000000000000000
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [6] : 554e444541444348454653000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [8] : 697066733a2f2f516d614c484d7162626438594e5934787a4b74585968435066
Arg [9] : 54764b5755794d4d6f72566155347838456f69746e2f70726572657665616c2f


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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