ETH Price: $3,333.41 (-2.69%)

Token

Savage Nation (Savage Nation)
 

Overview

Max Total Supply

7,777 Savage Nation

Holders

1,397

Market

Volume (24H)

0.0075 ETH

Min Price (24H)

$25.00 @ 0.007500 ETH

Max Price (24H)

$25.00 @ 0.007500 ETH
Balance
2 Savage Nation
0xd077B1cb1e0216609adfd9c4439C6d6B5787c8C2
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

10 unique fighters in the dystopian metaverse of Arcadia competing in the Savage Nation Tournament.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
SavageNation

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
No with 200 runs

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

// Contract by @AsteriaLabs
import "./Reg_ERC721Batch.sol";
import "./utils/Whitelist_Merkle.sol";
import "./utils/ERC173.sol";
import "./interfaces/DefaultOperatorFilterer.sol";

/// @title Savage Nation
/// @author Goku <@Suleman132446>
contract SavageNation is
    Reg_ERC721Batch,
    Whitelist_Merkle,
    ERC173,
    DefaultOperatorFilterer
{
    using MerkleProof for bytes32[];

    uint256 public whitelistPrice = 0.039 ether;
    uint256 public publicPrice = 0.059 ether;
    uint256 public maxPerWhitelist = 2;
    uint256 public maxPerPublic = 2;
    uint256 public maxSupply = 10000;

    /**
     @dev An enum representing the sale state
     */
    enum Sale {
        PAUSED,
        PRIVATE,
        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 {
        _setWhitelist(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_;
    }

    /**
     * @dev mint the token in whitelist sale
     *
     * @param proof_ : the proof for verificaton
     * @param qty_ : the quantity of mint
     */
    function mintWhitelist(bytes32[] memory proof_, uint256 qty_)
        external
        payable
        blockContracts
        isSaleState(Sale.PRIVATE)
        isWhitelisted(msg.sender, proof_, maxPerWhitelist, qty_)
    {
        uint _supply_ = totalSupply();
        require(_supply_ + qty_ <= maxSupply, "Exceeds supply");
        require(
            msg.value == qty_ * whitelistPrice,
            "Ether sent is not correct"
        );
        _mint(msg.sender, qty_);
        _consumeWhitelist(msg.sender, qty_);
    }

    /**
     * @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 15 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 3 of 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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_ );
	}
}

File 15 of 15 : Whitelist_Merkle.sol
// SPDX-License-Identifier: MIT

/**
 * Author: Lambdalf the White
 * Edit  : Squeebo
 */

pragma solidity 0.8.17;

import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

abstract contract Whitelist_Merkle {
    // Errors
    /**
     * @dev Thrown when trying to query the whitelist while it's not set
     */
    error Whitelist_NOT_SET();
    /**
     * @dev Thrown when `account` has consumed their alloted access and tries to query more
     *
     * @param account : address trying to access the whitelist
     */
    error Whitelist_CONSUMED(address account);
    /**
     * @dev Thrown when `account` does not have enough alloted access to fulfil their query
     *
     * @param account : address trying to access the whitelist
     */
    error Whitelist_FORBIDDEN(address account);

    bytes32 private _root;
    mapping(address => uint256) private _consumed;

    /**
     * @dev Ensures that `account_` has `qty_` alloted access on the whitelist.
     *
     * @param account_ : the address to validate access
     * @param proof_   : the Merkle proof to validate whitelist allocation
     * @param alloted_ : the max amount of whitelist spots allocated
     * @param qty_     : the amount of whitelist access requested
     */
    modifier isWhitelisted(
        address account_,
        bytes32[] memory proof_,
        uint256 alloted_,
        uint256 qty_
    ) {
        if (qty_ > alloted_) {
            revert Whitelist_FORBIDDEN(account_);
        }

        uint256 _allowed_ = checkWhitelistAllowance(account_, proof_, alloted_);

        if (_allowed_ < qty_) {
            revert Whitelist_FORBIDDEN(account_);
        }

        _;
    }

    /**
     * @dev Internal function setting the pass to protect the whitelist.
     *
     * @param root_ : the Merkle root to hold the whitelist
     */
    function _setWhitelist(bytes32 root_) internal virtual {
        _root = root_;
    }

    /**
     * @dev Returns the amount that `account_` is allowed to access from the whitelist.
     *
     * @param account_ : the address to validate access
     * @param proof_   : the Merkle proof to validate whitelist allocation
     *
     * @return uint256 : the total amount of whitelist allocation remaining for `account_`
     *
     * Requirements:
     *
     * - `_root` must be set.
     */
    function checkWhitelistAllowance(
        address account_,
        bytes32[] memory proof_,
        uint256 alloted_
    ) public view returns (uint256) {
        if (_root == 0) {
            revert Whitelist_NOT_SET();
        }

        if (_consumed[account_] >= alloted_) {
            revert Whitelist_CONSUMED(account_);
        }

        if (!_computeProof(account_, proof_)) {
            revert Whitelist_FORBIDDEN(account_);
        }

        uint256 _res_;
        unchecked {
            _res_ = alloted_ - _consumed[account_];
        }

        return _res_;
    }

    /**
     * @dev Processes the Merkle proof to determine if `account_` is whitelisted.
     *
     * @param account_ : the address to validate access
     * @param proof_   : the Merkle proof to validate whitelist allocation
     *
     * @return bool : whether `account_` is whitelisted or not
     */
    function _computeProof(address account_, bytes32[] memory proof_)
        private
        view
        returns (bool)
    {
        bytes32 leaf = keccak256(abi.encodePacked(account_));
        return MerkleProof.processProof(proof_, leaf) == _root;
    }

    /**
     * @dev Consumes `amount_` whitelist access passes from `account_`.
     *
     * @param account_ : the address to consume access from
     *
     * Note: Before calling this function, eligibility should be checked through {Whitelistable-checkWhitelistAllowance}.
     */
    function _consumeWhitelist(address account_, uint256 qty_) internal {
        unchecked {
            _consumed[account_] += qty_;
        }
    }
}

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":"address","name":"account_","type":"address"},{"internalType":"bytes32[]","name":"proof_","type":"bytes32[]"},{"internalType":"uint256","name":"alloted_","type":"uint256"}],"name":"checkWhitelistAllowance","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":"uint256","name":"qty_","type":"uint256"}],"name":"mintPublic","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof_","type":"bytes32[]"},{"internalType":"uint256","name":"qty_","type":"uint256"}],"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 SavageNation.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 SavageNation.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"}]

60806040526001600055668a8e4b1a3d8000600a5566d19c2ff9bf8000600b556002600c556002600d55612710600e556000600f60006101000a81548160ff021916908360028111156200005857620000576200034a565b5b02179055503480156200006a57600080fd5b506040516200563e3803806200563e83398181016040528101906200009091906200050c565b733cc6cdda760b79bafa08df41ecfa224f810dceb6600160006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156200029c57801562000162576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff16637d3e3dbe30846040518363ffffffff1660e01b8152600401620001289291906200060a565b600060405180830381600087803b1580156200014357600080fd5b505af115801562000158573d6000803e3d6000fd5b505050506200029b565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146200021c576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663a0af290330846040518363ffffffff1660e01b8152600401620001e29291906200060a565b600060405180830381600087803b158015620001fd57600080fd5b505af115801562000212573d6000803e3d6000fd5b505050506200029a565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff16634420e486306040518263ffffffff1660e01b815260040162000265919062000637565b600060405180830381600087803b1580156200028057600080fd5b505af115801562000295573d6000803e3d6000fd5b505050505b5b5b5050620002b1838383620002cb60201b60201c565b620002c2336200030660201b60201c565b50505062000986565b8260019081620002dc91906200089f565b508160029081620002ee91906200089f565b5080600690816200030091906200089f565b50505050565b80600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620003e28262000397565b810181811067ffffffffffffffff82111715620004045762000403620003a8565b5b80604052505050565b60006200041962000379565b9050620004278282620003d7565b919050565b600067ffffffffffffffff8211156200044a5762000449620003a8565b5b620004558262000397565b9050602081019050919050565b60005b838110156200048257808201518184015260208101905062000465565b60008484015250505050565b6000620004a56200049f846200042c565b6200040d565b905082815260208101848484011115620004c457620004c362000392565b5b620004d184828562000462565b509392505050565b600082601f830112620004f157620004f06200038d565b5b8151620005038482602086016200048e565b91505092915050565b60008060006060848603121562000528576200052762000383565b5b600084015167ffffffffffffffff81111562000549576200054862000388565b5b6200055786828701620004d9565b935050602084015167ffffffffffffffff8111156200057b576200057a62000388565b5b6200058986828701620004d9565b925050604084015167ffffffffffffffff811115620005ad57620005ac62000388565b5b620005bb86828701620004d9565b9150509250925092565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620005f282620005c5565b9050919050565b6200060481620005e5565b82525050565b6000604082019050620006216000830185620005f9565b620006306020830184620005f9565b9392505050565b60006020820190506200064e6000830184620005f9565b92915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620006a757607f821691505b602082108103620006bd57620006bc6200065f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620007277fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620006e8565b620007338683620006e8565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620007806200077a62000774846200074b565b62000755565b6200074b565b9050919050565b6000819050919050565b6200079c836200075f565b620007b4620007ab8262000787565b848454620006f5565b825550505050565b600090565b620007cb620007bc565b620007d881848462000791565b505050565b5b818110156200080057620007f4600082620007c1565b600181019050620007de565b5050565b601f8211156200084f576200081981620006c3565b6200082484620006d8565b8101602085101562000834578190505b6200084c6200084385620006d8565b830182620007dd565b50505b505050565b600082821c905092915050565b6000620008746000198460080262000854565b1980831691505092915050565b60006200088f838362000861565b9150826002028217905092915050565b620008aa8262000654565b67ffffffffffffffff811115620008c657620008c5620003a8565b5b620008d282546200068e565b620008df82828562000804565b600060209050601f83116001811462000917576000841562000902578287015190505b6200090e858262000881565b8655506200097e565b601f1984166200092786620006c3565b60005b8281101562000951578489015182556001820191506020850194506020810190506200092a565b868310156200097157848901516200096d601f89168262000861565b8355505b6001600288020188555050505b505050505050565b614ca880620009966000396000f3fe6080604052600436106102305760003560e01c80637d9128441161012e578063c87b56dd116100ab578063efd0cbf91161006f578063efd0cbf914610869578063f2fde38b14610885578063f3fef3a3146108ae578063f5aa406d146108d7578063fc1a1c361461090057610230565b8063c87b56dd14610770578063c95d83c6146107ad578063cfe1908d146107d6578063d5abeb0114610801578063e985e9c51461082c57610230565b8063a6d612f9116100f2578063a6d612f9146106bb578063a945bf80146106d7578063b88d4fde14610702578063bc63f02e1461072b578063c62752551461074757610230565b80637d912844146105d45780637e9845f5146106115780638da5cb5b1461063c57806395d89b4114610667578063a22cb4651461069257610230565b806342842e0e116101bc5780636352211e116101805780636352211e146104dd57806366cc5f0d1461051a5780636f8b44b01461054557806370a082311461056e578063717d57d3146105ab57610230565b806342842e0e146103fa5780634f6ccce71461042357806355f804b3146104605780635a67de0714610489578063603f4d52146104b257610230565b8063095ea7b311610203578063095ea7b31461030357806318160ddd1461032c57806323b872dd146103575780632f745c59146103805780633a602b4d146103bd57610230565b806301ffc9a71461023557806302c366bc1461027257806306fdde031461029b578063081812fc146102c6575b600080fd5b34801561024157600080fd5b5061025c6004803603810190610257919061367a565b61092b565b60405161026991906136c2565b60405180910390f35b34801561027e57600080fd5b5061029960048036038101906102949190613713565b610acd565b005b3480156102a757600080fd5b506102b0610b54565b6040516102bd91906137d0565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e89190613713565b610be2565b6040516102fa9190613833565b60405180910390f35b34801561030f57600080fd5b5061032a6004803603810190610325919061387a565b610c15565b005b34801561033857600080fd5b50610341610dec565b60405161034e91906138c9565b60405180910390f35b34801561036357600080fd5b5061037e600480360381019061037991906138e4565b610dfb565b005b34801561038c57600080fd5b506103a760048036038101906103a2919061387a565b610fdd565b6040516103b491906138c9565b60405180910390f35b3480156103c957600080fd5b506103e460048036038101906103df9190613937565b6110c8565b6040516103f191906138c9565b60405180910390f35b34801561040657600080fd5b50610421600480360381019061041c91906138e4565b6110e0565b005b34801561042f57600080fd5b5061044a60048036038101906104459190613713565b6112c2565b60405161045791906138c9565b60405180910390f35b34801561046c57600080fd5b5061048760048036038101906104829190613a99565b611323565b005b34801561049557600080fd5b506104b060048036038101906104ab9190613b07565b6113ac565b005b3480156104be57600080fd5b506104c7611456565b6040516104d49190613bab565b60405180910390f35b3480156104e957600080fd5b5061050460048036038101906104ff9190613713565b611469565b6040516105119190613833565b60405180910390f35b34801561052657600080fd5b5061052f6114c7565b60405161053c91906138c9565b60405180910390f35b34801561055157600080fd5b5061056c60048036038101906105679190613713565b6114cd565b005b34801561057a57600080fd5b5061059560048036038101906105909190613937565b6115e7565b6040516105a291906138c9565b60405180910390f35b3480156105b757600080fd5b506105d260048036038101906105cd9190613713565b6115f9565b005b3480156105e057600080fd5b506105fb60048036038101906105f69190613cc4565b611680565b60405161060891906138c9565b60405180910390f35b34801561061d57600080fd5b506106266117df565b60405161063391906138c9565b60405180910390f35b34801561064857600080fd5b506106516117f5565b60405161065e9190613833565b60405180910390f35b34801561067357600080fd5b5061067c61181f565b60405161068991906137d0565b60405180910390f35b34801561069e57600080fd5b506106b960048036038101906106b49190613d5f565b6118ad565b005b6106d560048036038101906106d09190613d9f565b611a20565b005b3480156106e357600080fd5b506106ec611c6e565b6040516106f991906138c9565b60405180910390f35b34801561070e57600080fd5b5061072960048036038101906107249190613e9c565b611c74565b005b61074560048036038101906107409190613f1f565b611e59565b005b34801561075357600080fd5b5061076e60048036038101906107699190613713565b611faf565b005b34801561077c57600080fd5b5061079760048036038101906107929190613713565b612036565b6040516107a491906137d0565b60405180910390f35b3480156107b957600080fd5b506107d460048036038101906107cf9190613713565b6120db565b005b3480156107e257600080fd5b506107eb612162565b6040516107f891906138c9565b60405180910390f35b34801561080d57600080fd5b50610816612168565b60405161082391906138c9565b60405180910390f35b34801561083857600080fd5b50610853600480360381019061084e9190613f5f565b61216e565b60405161086091906136c2565b60405180910390f35b610883600480360381019061087e9190613713565b612182565b005b34801561089157600080fd5b506108ac60048036038101906108a79190613937565b612406565b005b3480156108ba57600080fd5b506108d560048036038101906108d0919061387a565b612549565b005b3480156108e357600080fd5b506108fe60048036038101906108f99190613f9f565b612709565b005b34801561090c57600080fd5b50610915612792565b60405161092291906138c9565b60405180910390f35b60007f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806109f657507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a5e57507f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610ac657507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16610af16117f5565b73ffffffffffffffffffffffffffffffffffffffff1614610b4957806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401610b409190613833565b60405180910390fd5b81600d819055505050565b60018054610b6190613ffb565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8d90613ffb565b8015610bda5780601f10610baf57610100808354040283529160200191610bda565b820191906000526020600020905b815481529060010190602001808311610bbd57829003601f168201915b505050505081565b60036020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b80610c1f81612798565b610c6057806040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600401610c5791906138c9565b60405180910390fd5b60003390506000610c70846127b7565b90508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610ce257846040517ff2b21e1c000000000000000000000000000000000000000000000000000000008152600401610cd99190613833565b60405180910390fd5b6000610cef82848761287d565b905080610d37578183866040517f19f48dff000000000000000000000000000000000000000000000000000000008152600401610d2e9392919061402c565b60405180910390fd5b856003600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050505050565b6000610df6612936565b905090565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115610fcb573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e6d57610e68848484612945565b610fd7565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401610eb6929190614063565b602060405180830381865afa158015610ed3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef791906140a1565b8015610f8957506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401610f47929190614063565b602060405180830381865afa158015610f64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8891906140a1565b5b610fca57336040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401610fc19190613833565b60405180910390fd5b5b610fd6848484612945565b5b50505050565b6000610fe883612ae5565b821061102d5782826040517f374f8b4f0000000000000000000000000000000000000000000000000000000081526004016110249291906140ce565b60405180910390fd5b600080600190505b6000548110156110bf5761104881612798565b80156110875750611058816127b7565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b156110ac5781840361109d5780925050506110c2565b81806110a890614126565b9250505b80806110b790614126565b915050611035565b50505b92915050565b60106020528060005260406000206000915090505481565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156112b0573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036111525761114d848484612c42565b6112bc565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b815260040161119b929190614063565b602060405180830381865afa1580156111b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111dc91906140a1565b801561126e57506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b815260040161122c929190614063565b602060405180830381865afa158015611249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126d91906140a1565b5b6112af57336040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016112a69190613833565b60405180910390fd5b5b6112bb848484612c42565b5b50505050565b60006112cc6117df565b821061130f57816040517f125c19b000000000000000000000000000000000000000000000000000000000815260040161130691906138c9565b60405180910390fd5b60018261131c919061416e565b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166113476117f5565b73ffffffffffffffffffffffffffffffffffffffff161461139f57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016113969190613833565b60405180910390fd5b6113a882612c62565b5050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166113d06117f5565b73ffffffffffffffffffffffffffffffffffffffff161461142857806040517f55932a1b00000000000000000000000000000000000000000000000000000000815260040161141f9190613833565b60405180910390fd5b81600f60006101000a81548160ff0219169083600281111561144d5761144c613b34565b5b02179055505050565b600f60009054906101000a900460ff1681565b60008161147581612798565b6114b657806040517f1cf4d9a40000000000000000000000000000000000000000000000000000000081526004016114ad91906138c9565b60405180910390fd5b6114bf836127b7565b915050919050565b600c5481565b60003390508073ffffffffffffffffffffffffffffffffffffffff166114f16117f5565b73ffffffffffffffffffffffffffffffffffffffff161461154957806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016115409190613833565b60405180910390fd5b6000611553610dec565b9050808311611597576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161158e90614214565b60405180910390fd5b600e5483106115db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115d2906142a6565b60405180910390fd5b82600e81905550505050565b60006115f282612ae5565b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661161d6117f5565b73ffffffffffffffffffffffffffffffffffffffff161461167557806040517f55932a1b00000000000000000000000000000000000000000000000000000000815260040161166c9190613833565b60405180910390fd5b81600a819055505050565b60008060001b600754036116c0576040517f93dff14200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541061174357836040517f6acdb09500000000000000000000000000000000000000000000000000000000815260040161173a9190613833565b60405180910390fd5b61174d8484612c75565b61178e57836040517f186a628d0000000000000000000000000000000000000000000000000000000081526004016117859190613833565b60405180910390fd5b6000600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483039050809150509392505050565b600060016000546117f091906142c6565b905090565b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6002805461182c90613ffb565b80601f016020809104026020016040519081016040528092919081815260200182805461185890613ffb565b80156118a55780601f1061187a576101008083540402835291602001916118a5565b820191906000526020600020905b81548152906001019060200180831161188857829003601f168201915b505050505081565b60003390508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361192257826040517ff2b21e1c0000000000000000000000000000000000000000000000000000000081526004016119199190613833565b60405180910390fd5b81600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3184604051611a1391906136c2565b60405180910390a3505050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614611a8e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a8590614346565b60405180910390fd5b6001806002811115611aa357611aa2613b34565b5b600f60009054906101000a900460ff166002811115611ac557611ac4613b34565b5b14611b05576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611afc906143b2565b60405180910390fd5b3383600c548481811115611b5057836040517f186a628d000000000000000000000000000000000000000000000000000000008152600401611b479190613833565b60405180910390fd5b6000611b5d858585611680565b905081811015611ba457846040517f186a628d000000000000000000000000000000000000000000000000000000008152600401611b9b9190613833565b60405180910390fd5b6000611bae610dec565b9050600e548882611bbf919061416e565b1115611c00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bf79061441e565b60405180910390fd5b600a5488611c0e919061443e565b3414611c4f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c46906144cc565b60405180910390fd5b611c593389612cb8565b611c633389612e73565b505050505050505050565b600b5481565b8360006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115611e45573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611ce757611ce285858585612ec4565b611e52565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401611d30929190614063565b602060405180830381865afa158015611d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7191906140a1565b8015611e0357506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401611dc1929190614063565b602060405180830381865afa158015611dde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e0291906140a1565b5b611e4457336040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401611e3b9190613833565b60405180910390fd5b5b611e5185858585612ec4565b5b5050505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611e7d6117f5565b73ffffffffffffffffffffffffffffffffffffffff1614611ed557806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401611ecc9190613833565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614611f43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f3a90614346565b60405180910390fd5b6000611f4d610dec565b9050600e548482611f5e919061416e565b1115611f9f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f969061441e565b60405180910390fd5b611fa98385612cb8565b50505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611fd36117f5565b73ffffffffffffffffffffffffffffffffffffffff161461202b57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016120229190613833565b60405180910390fd5b81600b819055505050565b60608161204281612798565b61208357806040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260040161207a91906138c9565b60405180910390fd5b60006006805461209290613ffb565b9050116120a7576120a283612f22565b6120d3565b60066120b284612f22565b6040516020016120c39291906145c0565b6040516020818303038152906040525b915050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166120ff6117f5565b73ffffffffffffffffffffffffffffffffffffffff161461215757806040517f55932a1b00000000000000000000000000000000000000000000000000000000815260040161214e9190613833565b60405180910390fd5b81600c819055505050565b600d5481565b600e5481565b600061217a8383613082565b905092915050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146121f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121e790614346565b60405180910390fd5b600280600281111561220557612204613b34565b5b600f60009054906101000a900460ff16600281111561222757612226613b34565b5b14612267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225e906143b2565b60405180910390fd5b6000612271610dec565b9050600d5483601060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546122c1919061416e565b1115612302576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122f990614630565b60405180910390fd5b600e548382612311919061416e565b1115612352576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123499061441e565b60405180910390fd5b600b5483612360919061443e565b34146123a1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612398906144cc565b60405180910390fd5b6123ab3384612cb8565b82601060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546123fa919061416e565b92505081905550505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661242a6117f5565b73ffffffffffffffffffffffffffffffffffffffff161461248257806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016124799190613833565b60405180910390fd5b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905082600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661256d6117f5565b73ffffffffffffffffffffffffffffffffffffffff16146125c557806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016125bc9190613833565b60405180910390fd5b60004790506000811161260d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126049061469c565b60405180910390fd5b80831115612650576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161264790614708565b60405180910390fd5b600084905060008173ffffffffffffffffffffffffffffffffffffffff168560405161267b90614759565b60006040518083038185875af1925050503d80600081146126b8576040519150601f19603f3d011682016040523d82523d6000602084013e6126bd565b606091505b5050905080612701576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126f8906147ba565b60405180910390fd5b505050505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661272d6117f5565b73ffffffffffffffffffffffffffffffffffffffff161461278557806040517f55932a1b00000000000000000000000000000000000000000000000000000000815260040161277c9190613833565b60405180910390fd5b61278e82613116565b5050565b600a5481565b60008082036127aa57600090506127b2565b600054821090505b919050565b60008082905060006005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612873578180612835906147da565b9250506005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506127f6565b8092505050919050565b6000808473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061291857506003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b8061292957506129288585613082565b5b9050809150509392505050565b60006129406117df565b905090565b8061294f81612798565b61299057806040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260040161298791906138c9565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036129f6576040517f14242cb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003390506000612a06846127b7565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614612a7c578086856040517fe02b28e7000000000000000000000000000000000000000000000000000000008152600401612a739392919061402c565b60405180910390fd5b6000612a8982848761287d565b905080612ad1578183866040517f19f48dff000000000000000000000000000000000000000000000000000000008152600401612ac89392919061402c565b60405180910390fd5b612adc828787613120565b50505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612b235760009050612c3d565b60008080600190505b600054811015612c3657612b3f81612798565b15612c2557600073ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612be2576005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b8173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612c24578280612c2090614126565b9350505b5b80612c2f90614126565b9050612b2c565b5081925050505b919050565b612c5d83838360405180602001604052806000815250611c74565b505050565b8060069081612c71919061499a565b5050565b60008083604051602001612c899190614ab4565b604051602081830303815290604052805190602001209050600754612cae8483613408565b1491505092915050565b60008054905060008282612ccc919061416e565b90506000600182612cdd91906142c6565b9050846005600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082811115612d8c57846005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b81600081905550612daf600086856040518060200160405280600081525061345e565b612df057846040517f015be56a000000000000000000000000000000000000000000000000000000008152600401612de79190613833565b60405180910390fd5b60008390505b82811015612e6b57808673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a480612e6490614126565b9050612df6565b505050505050565b80600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505050565b612ecf848484610dfb565b612edb8484848461345e565b612f1c57826040517f015be56a000000000000000000000000000000000000000000000000000000008152600401612f139190613833565b60405180910390fd5b50505050565b606060008203612f69576040518060400160405280600181526020017f3000000000000000000000000000000000000000000000000000000000000000815250905061307d565b600082905060005b60008214612f9b578080612f8490614126565b915050600a82612f949190614afe565b9150612f71565b60008167ffffffffffffffff811115612fb757612fb661396e565b5b6040519080825280601f01601f191660200182016040528015612fe95781602001600182028036833780820191505090505b5090505b600085146130765760018261300291906142c6565b9150600a856130119190614b2f565b603061301d919061416e565b60f81b81838151811061303357613032614b60565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a8561306f9190614afe565b9450612fed565b8093505050505b919050565b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b8060078190555050565b60006003600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060018211613184576001613192565b60018261319191906142c6565b5b905060006001836131a3919061416e565b9050600083831080156131bb57506131ba83612798565b5b80156132265750600073ffffffffffffffffffffffffffffffffffffffff166005600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b9050600061323383612798565b801561329e5750600073ffffffffffffffffffffffffffffffffffffffff166005600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b905081156132f957866005600086815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b801561335257866005600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b856005600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050505050565b60008082905060005b84518110156134535761343e8286838151811061343157613430614b60565b5b60200260200101516135cc565b9150808061344b90614126565b915050613411565b508091505092915050565b600080843b905060008111156135be578473ffffffffffffffffffffffffffffffffffffffff1663150b7a02338887876040518563ffffffff1660e01b81526004016134ad9493929190614be4565b6020604051808303816000875af19250505080156134e957506040513d601f19601f820116820180604052508101906134e69190614c45565b60015b61356d573d8060008114613519576040519150601f19603f3d011682016040523d82523d6000602084013e61351e565b606091505b50600081510361356557856040517f015be56a00000000000000000000000000000000000000000000000000000000815260040161355c9190613833565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614925050506135c4565b60019150505b949350505050565b60008183106135e4576135df82846135f7565b6135ef565b6135ee83836135f7565b5b905092915050565b600082600052816020526040600020905092915050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61365781613622565b811461366257600080fd5b50565b6000813590506136748161364e565b92915050565b6000602082840312156136905761368f613618565b5b600061369e84828501613665565b91505092915050565b60008115159050919050565b6136bc816136a7565b82525050565b60006020820190506136d760008301846136b3565b92915050565b6000819050919050565b6136f0816136dd565b81146136fb57600080fd5b50565b60008135905061370d816136e7565b92915050565b60006020828403121561372957613728613618565b5b6000613737848285016136fe565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561377a57808201518184015260208101905061375f565b60008484015250505050565b6000601f19601f8301169050919050565b60006137a282613740565b6137ac818561374b565b93506137bc81856020860161375c565b6137c581613786565b840191505092915050565b600060208201905081810360008301526137ea8184613797565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061381d826137f2565b9050919050565b61382d81613812565b82525050565b60006020820190506138486000830184613824565b92915050565b61385781613812565b811461386257600080fd5b50565b6000813590506138748161384e565b92915050565b6000806040838503121561389157613890613618565b5b600061389f85828601613865565b92505060206138b0858286016136fe565b9150509250929050565b6138c3816136dd565b82525050565b60006020820190506138de60008301846138ba565b92915050565b6000806000606084860312156138fd576138fc613618565b5b600061390b86828701613865565b935050602061391c86828701613865565b925050604061392d868287016136fe565b9150509250925092565b60006020828403121561394d5761394c613618565b5b600061395b84828501613865565b91505092915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6139a682613786565b810181811067ffffffffffffffff821117156139c5576139c461396e565b5b80604052505050565b60006139d861360e565b90506139e4828261399d565b919050565b600067ffffffffffffffff821115613a0457613a0361396e565b5b613a0d82613786565b9050602081019050919050565b82818337600083830152505050565b6000613a3c613a37846139e9565b6139ce565b905082815260208101848484011115613a5857613a57613969565b5b613a63848285613a1a565b509392505050565b600082601f830112613a8057613a7f613964565b5b8135613a90848260208601613a29565b91505092915050565b600060208284031215613aaf57613aae613618565b5b600082013567ffffffffffffffff811115613acd57613acc61361d565b5b613ad984828501613a6b565b91505092915050565b60038110613aef57600080fd5b50565b600081359050613b0181613ae2565b92915050565b600060208284031215613b1d57613b1c613618565b5b6000613b2b84828501613af2565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110613b7457613b73613b34565b5b50565b6000819050613b8582613b63565b919050565b6000613b9582613b77565b9050919050565b613ba581613b8a565b82525050565b6000602082019050613bc06000830184613b9c565b92915050565b600067ffffffffffffffff821115613be157613be061396e565b5b602082029050602081019050919050565b600080fd5b6000819050919050565b613c0a81613bf7565b8114613c1557600080fd5b50565b600081359050613c2781613c01565b92915050565b6000613c40613c3b84613bc6565b6139ce565b90508083825260208201905060208402830185811115613c6357613c62613bf2565b5b835b81811015613c8c5780613c788882613c18565b845260208401935050602081019050613c65565b5050509392505050565b600082601f830112613cab57613caa613964565b5b8135613cbb848260208601613c2d565b91505092915050565b600080600060608486031215613cdd57613cdc613618565b5b6000613ceb86828701613865565b935050602084013567ffffffffffffffff811115613d0c57613d0b61361d565b5b613d1886828701613c96565b9250506040613d29868287016136fe565b9150509250925092565b613d3c816136a7565b8114613d4757600080fd5b50565b600081359050613d5981613d33565b92915050565b60008060408385031215613d7657613d75613618565b5b6000613d8485828601613865565b9250506020613d9585828601613d4a565b9150509250929050565b60008060408385031215613db657613db5613618565b5b600083013567ffffffffffffffff811115613dd457613dd361361d565b5b613de085828601613c96565b9250506020613df1858286016136fe565b9150509250929050565b600067ffffffffffffffff821115613e1657613e1561396e565b5b613e1f82613786565b9050602081019050919050565b6000613e3f613e3a84613dfb565b6139ce565b905082815260208101848484011115613e5b57613e5a613969565b5b613e66848285613a1a565b509392505050565b600082601f830112613e8357613e82613964565b5b8135613e93848260208601613e2c565b91505092915050565b60008060008060808587031215613eb657613eb5613618565b5b6000613ec487828801613865565b9450506020613ed587828801613865565b9350506040613ee6878288016136fe565b925050606085013567ffffffffffffffff811115613f0757613f0661361d565b5b613f1387828801613e6e565b91505092959194509250565b60008060408385031215613f3657613f35613618565b5b6000613f44858286016136fe565b9250506020613f5585828601613865565b9150509250929050565b60008060408385031215613f7657613f75613618565b5b6000613f8485828601613865565b9250506020613f9585828601613865565b9150509250929050565b600060208284031215613fb557613fb4613618565b5b6000613fc384828501613c18565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061401357607f821691505b60208210810361402657614025613fcc565b5b50919050565b60006060820190506140416000830186613824565b61404e6020830185613824565b61405b60408301846138ba565b949350505050565b60006040820190506140786000830185613824565b6140856020830184613824565b9392505050565b60008151905061409b81613d33565b92915050565b6000602082840312156140b7576140b6613618565b5b60006140c58482850161408c565b91505092915050565b60006040820190506140e36000830185613824565b6140f060208301846138ba565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614131826136dd565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614163576141626140f7565b5b600182019050919050565b6000614179826136dd565b9150614184836136dd565b925082820190508082111561419c5761419b6140f7565b5b92915050565b7f4d617820737570706c792073686f756c6420626520677265617465722074686160008201527f6e2063757272656e7420737570706c7900000000000000000000000000000000602082015250565b60006141fe60308361374b565b9150614209826141a2565b604082019050919050565b6000602082019050818103600083015261422d816141f1565b9050919050565b7f4d617820737570706c792073686f756c6420626520677265617465722074686160008201527f6e2070726576696f7573206d617820737570706c790000000000000000000000602082015250565b600061429060358361374b565b915061429b82614234565b604082019050919050565b600060208201905081810360008301526142bf81614283565b9050919050565b60006142d1826136dd565b91506142dc836136dd565b92508282039050818111156142f4576142f36140f7565b5b92915050565b7f4e6f20736d61727420636f6e7472616374732061726520616c6c6f7765640000600082015250565b6000614330601e8361374b565b915061433b826142fa565b602082019050919050565b6000602082019050818103600083015261435f81614323565b9050919050565b7f53616c65206e6f74206163746976650000000000000000000000000000000000600082015250565b600061439c600f8361374b565b91506143a782614366565b602082019050919050565b600060208201905081810360008301526143cb8161438f565b9050919050565b7f4578636565647320737570706c79000000000000000000000000000000000000600082015250565b6000614408600e8361374b565b9150614413826143d2565b602082019050919050565b60006020820190508181036000830152614437816143fb565b9050919050565b6000614449826136dd565b9150614454836136dd565b9250828202614462816136dd565b91508282048414831517614479576144786140f7565b5b5092915050565b7f45746865722073656e74206973206e6f7420636f727265637400000000000000600082015250565b60006144b660198361374b565b91506144c182614480565b602082019050919050565b600060208201905081810360008301526144e5816144a9565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461451981613ffb565b61452381866144ec565b9450600182166000811461453e576001811461455357614586565b60ff1983168652811515820286019350614586565b61455c856144f7565b60005b8381101561457e5781548189015260018201915060208101905061455f565b838801955050505b50505092915050565b600061459a82613740565b6145a481856144ec565b93506145b481856020860161375c565b80840191505092915050565b60006145cc828561450c565b91506145d8828461458f565b91508190509392505050565b7f45786365656473206d696e74207065722077616c6c6574000000000000000000600082015250565b600061461a60178361374b565b9150614625826145e4565b602082019050919050565b600060208201905081810360008301526146498161460d565b9050919050565b7f4e6f2062616c616e636520746f20776974686472617700000000000000000000600082015250565b600061468660168361374b565b915061469182614650565b602082019050919050565b600060208201905081810360008301526146b581614679565b9050919050565b7f416d6f756e74206973206e6f742076616c696400000000000000000000000000600082015250565b60006146f260138361374b565b91506146fd826146bc565b602082019050919050565b60006020820190508181036000830152614721816146e5565b9050919050565b600081905092915050565b50565b6000614743600083614728565b915061474e82614733565b600082019050919050565b600061476482614736565b9150819050919050565b7f5472616e73616374696f6e206661696c65640000000000000000000000000000600082015250565b60006147a460128361374b565b91506147af8261476e565b602082019050919050565b600060208201905081810360008301526147d381614797565b9050919050565b60006147e5826136dd565b9150600082036147f8576147f76140f7565b5b600182039050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026148507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614813565b61485a8683614813565b95508019841693508086168417925050509392505050565b6000819050919050565b600061489761489261488d846136dd565b614872565b6136dd565b9050919050565b6000819050919050565b6148b18361487c565b6148c56148bd8261489e565b848454614820565b825550505050565b600090565b6148da6148cd565b6148e58184846148a8565b505050565b5b81811015614909576148fe6000826148d2565b6001810190506148eb565b5050565b601f82111561494e5761491f816144f7565b61492884614803565b81016020851015614937578190505b61494b61494385614803565b8301826148ea565b50505b505050565b600082821c905092915050565b600061497160001984600802614953565b1980831691505092915050565b600061498a8383614960565b9150826002028217905092915050565b6149a382613740565b67ffffffffffffffff8111156149bc576149bb61396e565b5b6149c68254613ffb565b6149d182828561490d565b600060209050601f831160018114614a0457600084156149f2578287015190505b6149fc858261497e565b865550614a64565b601f198416614a12866144f7565b60005b82811015614a3a57848901518255600182019150602085019450602081019050614a15565b86831015614a575784890151614a53601f891682614960565b8355505b6001600288020188555050505b505050505050565b60008160601b9050919050565b6000614a8482614a6c565b9050919050565b6000614a9682614a79565b9050919050565b614aae614aa982613812565b614a8b565b82525050565b6000614ac08284614a9d565b60148201915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614b09826136dd565b9150614b14836136dd565b925082614b2457614b23614acf565b5b828204905092915050565b6000614b3a826136dd565b9150614b45836136dd565b925082614b5557614b54614acf565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050919050565b600082825260208201905092915050565b6000614bb682614b8f565b614bc08185614b9a565b9350614bd081856020860161375c565b614bd981613786565b840191505092915050565b6000608082019050614bf96000830187613824565b614c066020830186613824565b614c1360408301856138ba565b8181036060830152614c258184614bab565b905095945050505050565b600081519050614c3f8161364e565b92915050565b600060208284031215614c5b57614c5a613618565b5b6000614c6984828501614c30565b9150509291505056fea2646970667358221220f421f832a83304ef944ee0444694434aa2fe84d630e552f4a840794ae955487b64736f6c63430008110033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000d536176616765204e6174696f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d536176616765204e6174696f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005868747470733a2f2f7361766167656e6174696f6e2e6d7970696e6174612e636c6f75642f697066732f516d5833517a6e36654c35484e374548413650657475735732324455776f756d524c31444e696d315153745147482f0000000000000000

Deployed Bytecode

0x6080604052600436106102305760003560e01c80637d9128441161012e578063c87b56dd116100ab578063efd0cbf91161006f578063efd0cbf914610869578063f2fde38b14610885578063f3fef3a3146108ae578063f5aa406d146108d7578063fc1a1c361461090057610230565b8063c87b56dd14610770578063c95d83c6146107ad578063cfe1908d146107d6578063d5abeb0114610801578063e985e9c51461082c57610230565b8063a6d612f9116100f2578063a6d612f9146106bb578063a945bf80146106d7578063b88d4fde14610702578063bc63f02e1461072b578063c62752551461074757610230565b80637d912844146105d45780637e9845f5146106115780638da5cb5b1461063c57806395d89b4114610667578063a22cb4651461069257610230565b806342842e0e116101bc5780636352211e116101805780636352211e146104dd57806366cc5f0d1461051a5780636f8b44b01461054557806370a082311461056e578063717d57d3146105ab57610230565b806342842e0e146103fa5780634f6ccce71461042357806355f804b3146104605780635a67de0714610489578063603f4d52146104b257610230565b8063095ea7b311610203578063095ea7b31461030357806318160ddd1461032c57806323b872dd146103575780632f745c59146103805780633a602b4d146103bd57610230565b806301ffc9a71461023557806302c366bc1461027257806306fdde031461029b578063081812fc146102c6575b600080fd5b34801561024157600080fd5b5061025c6004803603810190610257919061367a565b61092b565b60405161026991906136c2565b60405180910390f35b34801561027e57600080fd5b5061029960048036038101906102949190613713565b610acd565b005b3480156102a757600080fd5b506102b0610b54565b6040516102bd91906137d0565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e89190613713565b610be2565b6040516102fa9190613833565b60405180910390f35b34801561030f57600080fd5b5061032a6004803603810190610325919061387a565b610c15565b005b34801561033857600080fd5b50610341610dec565b60405161034e91906138c9565b60405180910390f35b34801561036357600080fd5b5061037e600480360381019061037991906138e4565b610dfb565b005b34801561038c57600080fd5b506103a760048036038101906103a2919061387a565b610fdd565b6040516103b491906138c9565b60405180910390f35b3480156103c957600080fd5b506103e460048036038101906103df9190613937565b6110c8565b6040516103f191906138c9565b60405180910390f35b34801561040657600080fd5b50610421600480360381019061041c91906138e4565b6110e0565b005b34801561042f57600080fd5b5061044a60048036038101906104459190613713565b6112c2565b60405161045791906138c9565b60405180910390f35b34801561046c57600080fd5b5061048760048036038101906104829190613a99565b611323565b005b34801561049557600080fd5b506104b060048036038101906104ab9190613b07565b6113ac565b005b3480156104be57600080fd5b506104c7611456565b6040516104d49190613bab565b60405180910390f35b3480156104e957600080fd5b5061050460048036038101906104ff9190613713565b611469565b6040516105119190613833565b60405180910390f35b34801561052657600080fd5b5061052f6114c7565b60405161053c91906138c9565b60405180910390f35b34801561055157600080fd5b5061056c60048036038101906105679190613713565b6114cd565b005b34801561057a57600080fd5b5061059560048036038101906105909190613937565b6115e7565b6040516105a291906138c9565b60405180910390f35b3480156105b757600080fd5b506105d260048036038101906105cd9190613713565b6115f9565b005b3480156105e057600080fd5b506105fb60048036038101906105f69190613cc4565b611680565b60405161060891906138c9565b60405180910390f35b34801561061d57600080fd5b506106266117df565b60405161063391906138c9565b60405180910390f35b34801561064857600080fd5b506106516117f5565b60405161065e9190613833565b60405180910390f35b34801561067357600080fd5b5061067c61181f565b60405161068991906137d0565b60405180910390f35b34801561069e57600080fd5b506106b960048036038101906106b49190613d5f565b6118ad565b005b6106d560048036038101906106d09190613d9f565b611a20565b005b3480156106e357600080fd5b506106ec611c6e565b6040516106f991906138c9565b60405180910390f35b34801561070e57600080fd5b5061072960048036038101906107249190613e9c565b611c74565b005b61074560048036038101906107409190613f1f565b611e59565b005b34801561075357600080fd5b5061076e60048036038101906107699190613713565b611faf565b005b34801561077c57600080fd5b5061079760048036038101906107929190613713565b612036565b6040516107a491906137d0565b60405180910390f35b3480156107b957600080fd5b506107d460048036038101906107cf9190613713565b6120db565b005b3480156107e257600080fd5b506107eb612162565b6040516107f891906138c9565b60405180910390f35b34801561080d57600080fd5b50610816612168565b60405161082391906138c9565b60405180910390f35b34801561083857600080fd5b50610853600480360381019061084e9190613f5f565b61216e565b60405161086091906136c2565b60405180910390f35b610883600480360381019061087e9190613713565b612182565b005b34801561089157600080fd5b506108ac60048036038101906108a79190613937565b612406565b005b3480156108ba57600080fd5b506108d560048036038101906108d0919061387a565b612549565b005b3480156108e357600080fd5b506108fe60048036038101906108f99190613f9f565b612709565b005b34801561090c57600080fd5b50610915612792565b60405161092291906138c9565b60405180910390f35b60007f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806109f657507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a5e57507f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610ac657507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16610af16117f5565b73ffffffffffffffffffffffffffffffffffffffff1614610b4957806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401610b409190613833565b60405180910390fd5b81600d819055505050565b60018054610b6190613ffb565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8d90613ffb565b8015610bda5780601f10610baf57610100808354040283529160200191610bda565b820191906000526020600020905b815481529060010190602001808311610bbd57829003601f168201915b505050505081565b60036020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b80610c1f81612798565b610c6057806040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600401610c5791906138c9565b60405180910390fd5b60003390506000610c70846127b7565b90508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610ce257846040517ff2b21e1c000000000000000000000000000000000000000000000000000000008152600401610cd99190613833565b60405180910390fd5b6000610cef82848761287d565b905080610d37578183866040517f19f48dff000000000000000000000000000000000000000000000000000000008152600401610d2e9392919061402c565b60405180910390fd5b856003600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050505050565b6000610df6612936565b905090565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115610fcb573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e6d57610e68848484612945565b610fd7565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401610eb6929190614063565b602060405180830381865afa158015610ed3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef791906140a1565b8015610f8957506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401610f47929190614063565b602060405180830381865afa158015610f64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8891906140a1565b5b610fca57336040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401610fc19190613833565b60405180910390fd5b5b610fd6848484612945565b5b50505050565b6000610fe883612ae5565b821061102d5782826040517f374f8b4f0000000000000000000000000000000000000000000000000000000081526004016110249291906140ce565b60405180910390fd5b600080600190505b6000548110156110bf5761104881612798565b80156110875750611058816127b7565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b156110ac5781840361109d5780925050506110c2565b81806110a890614126565b9250505b80806110b790614126565b915050611035565b50505b92915050565b60106020528060005260406000206000915090505481565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156112b0573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036111525761114d848484612c42565b6112bc565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b815260040161119b929190614063565b602060405180830381865afa1580156111b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111dc91906140a1565b801561126e57506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b815260040161122c929190614063565b602060405180830381865afa158015611249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126d91906140a1565b5b6112af57336040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016112a69190613833565b60405180910390fd5b5b6112bb848484612c42565b5b50505050565b60006112cc6117df565b821061130f57816040517f125c19b000000000000000000000000000000000000000000000000000000000815260040161130691906138c9565b60405180910390fd5b60018261131c919061416e565b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166113476117f5565b73ffffffffffffffffffffffffffffffffffffffff161461139f57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016113969190613833565b60405180910390fd5b6113a882612c62565b5050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166113d06117f5565b73ffffffffffffffffffffffffffffffffffffffff161461142857806040517f55932a1b00000000000000000000000000000000000000000000000000000000815260040161141f9190613833565b60405180910390fd5b81600f60006101000a81548160ff0219169083600281111561144d5761144c613b34565b5b02179055505050565b600f60009054906101000a900460ff1681565b60008161147581612798565b6114b657806040517f1cf4d9a40000000000000000000000000000000000000000000000000000000081526004016114ad91906138c9565b60405180910390fd5b6114bf836127b7565b915050919050565b600c5481565b60003390508073ffffffffffffffffffffffffffffffffffffffff166114f16117f5565b73ffffffffffffffffffffffffffffffffffffffff161461154957806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016115409190613833565b60405180910390fd5b6000611553610dec565b9050808311611597576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161158e90614214565b60405180910390fd5b600e5483106115db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115d2906142a6565b60405180910390fd5b82600e81905550505050565b60006115f282612ae5565b9050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661161d6117f5565b73ffffffffffffffffffffffffffffffffffffffff161461167557806040517f55932a1b00000000000000000000000000000000000000000000000000000000815260040161166c9190613833565b60405180910390fd5b81600a819055505050565b60008060001b600754036116c0576040517f93dff14200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541061174357836040517f6acdb09500000000000000000000000000000000000000000000000000000000815260040161173a9190613833565b60405180910390fd5b61174d8484612c75565b61178e57836040517f186a628d0000000000000000000000000000000000000000000000000000000081526004016117859190613833565b60405180910390fd5b6000600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483039050809150509392505050565b600060016000546117f091906142c6565b905090565b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6002805461182c90613ffb565b80601f016020809104026020016040519081016040528092919081815260200182805461185890613ffb565b80156118a55780601f1061187a576101008083540402835291602001916118a5565b820191906000526020600020905b81548152906001019060200180831161188857829003601f168201915b505050505081565b60003390508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361192257826040517ff2b21e1c0000000000000000000000000000000000000000000000000000000081526004016119199190613833565b60405180910390fd5b81600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3184604051611a1391906136c2565b60405180910390a3505050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614611a8e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a8590614346565b60405180910390fd5b6001806002811115611aa357611aa2613b34565b5b600f60009054906101000a900460ff166002811115611ac557611ac4613b34565b5b14611b05576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611afc906143b2565b60405180910390fd5b3383600c548481811115611b5057836040517f186a628d000000000000000000000000000000000000000000000000000000008152600401611b479190613833565b60405180910390fd5b6000611b5d858585611680565b905081811015611ba457846040517f186a628d000000000000000000000000000000000000000000000000000000008152600401611b9b9190613833565b60405180910390fd5b6000611bae610dec565b9050600e548882611bbf919061416e565b1115611c00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bf79061441e565b60405180910390fd5b600a5488611c0e919061443e565b3414611c4f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c46906144cc565b60405180910390fd5b611c593389612cb8565b611c633389612e73565b505050505050505050565b600b5481565b8360006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115611e45573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611ce757611ce285858585612ec4565b611e52565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401611d30929190614063565b602060405180830381865afa158015611d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7191906140a1565b8015611e0357506daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401611dc1929190614063565b602060405180830381865afa158015611dde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e0291906140a1565b5b611e4457336040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401611e3b9190613833565b60405180910390fd5b5b611e5185858585612ec4565b5b5050505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611e7d6117f5565b73ffffffffffffffffffffffffffffffffffffffff1614611ed557806040517f55932a1b000000000000000000000000000000000000000000000000000000008152600401611ecc9190613833565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614611f43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f3a90614346565b60405180910390fd5b6000611f4d610dec565b9050600e548482611f5e919061416e565b1115611f9f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f969061441e565b60405180910390fd5b611fa98385612cb8565b50505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff16611fd36117f5565b73ffffffffffffffffffffffffffffffffffffffff161461202b57806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016120229190613833565b60405180910390fd5b81600b819055505050565b60608161204281612798565b61208357806040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260040161207a91906138c9565b60405180910390fd5b60006006805461209290613ffb565b9050116120a7576120a283612f22565b6120d3565b60066120b284612f22565b6040516020016120c39291906145c0565b6040516020818303038152906040525b915050919050565b60003390508073ffffffffffffffffffffffffffffffffffffffff166120ff6117f5565b73ffffffffffffffffffffffffffffffffffffffff161461215757806040517f55932a1b00000000000000000000000000000000000000000000000000000000815260040161214e9190613833565b60405180910390fd5b81600c819055505050565b600d5481565b600e5481565b600061217a8383613082565b905092915050565b3373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146121f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121e790614346565b60405180910390fd5b600280600281111561220557612204613b34565b5b600f60009054906101000a900460ff16600281111561222757612226613b34565b5b14612267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225e906143b2565b60405180910390fd5b6000612271610dec565b9050600d5483601060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546122c1919061416e565b1115612302576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122f990614630565b60405180910390fd5b600e548382612311919061416e565b1115612352576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123499061441e565b60405180910390fd5b600b5483612360919061443e565b34146123a1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612398906144cc565b60405180910390fd5b6123ab3384612cb8565b82601060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546123fa919061416e565b92505081905550505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661242a6117f5565b73ffffffffffffffffffffffffffffffffffffffff161461248257806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016124799190613833565b60405180910390fd5b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905082600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661256d6117f5565b73ffffffffffffffffffffffffffffffffffffffff16146125c557806040517f55932a1b0000000000000000000000000000000000000000000000000000000081526004016125bc9190613833565b60405180910390fd5b60004790506000811161260d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126049061469c565b60405180910390fd5b80831115612650576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161264790614708565b60405180910390fd5b600084905060008173ffffffffffffffffffffffffffffffffffffffff168560405161267b90614759565b60006040518083038185875af1925050503d80600081146126b8576040519150601f19603f3d011682016040523d82523d6000602084013e6126bd565b606091505b5050905080612701576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126f8906147ba565b60405180910390fd5b505050505050565b60003390508073ffffffffffffffffffffffffffffffffffffffff1661272d6117f5565b73ffffffffffffffffffffffffffffffffffffffff161461278557806040517f55932a1b00000000000000000000000000000000000000000000000000000000815260040161277c9190613833565b60405180910390fd5b61278e82613116565b5050565b600a5481565b60008082036127aa57600090506127b2565b600054821090505b919050565b60008082905060006005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612873578180612835906147da565b9250506005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506127f6565b8092505050919050565b6000808473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061291857506003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b8061292957506129288585613082565b5b9050809150509392505050565b60006129406117df565b905090565b8061294f81612798565b61299057806040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260040161298791906138c9565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036129f6576040517f14242cb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003390506000612a06846127b7565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614612a7c578086856040517fe02b28e7000000000000000000000000000000000000000000000000000000008152600401612a739392919061402c565b60405180910390fd5b6000612a8982848761287d565b905080612ad1578183866040517f19f48dff000000000000000000000000000000000000000000000000000000008152600401612ac89392919061402c565b60405180910390fd5b612adc828787613120565b50505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612b235760009050612c3d565b60008080600190505b600054811015612c3657612b3f81612798565b15612c2557600073ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612be2576005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b8173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612c24578280612c2090614126565b9350505b5b80612c2f90614126565b9050612b2c565b5081925050505b919050565b612c5d83838360405180602001604052806000815250611c74565b505050565b8060069081612c71919061499a565b5050565b60008083604051602001612c899190614ab4565b604051602081830303815290604052805190602001209050600754612cae8483613408565b1491505092915050565b60008054905060008282612ccc919061416e565b90506000600182612cdd91906142c6565b9050846005600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082811115612d8c57846005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b81600081905550612daf600086856040518060200160405280600081525061345e565b612df057846040517f015be56a000000000000000000000000000000000000000000000000000000008152600401612de79190613833565b60405180910390fd5b60008390505b82811015612e6b57808673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a480612e6490614126565b9050612df6565b505050505050565b80600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505050565b612ecf848484610dfb565b612edb8484848461345e565b612f1c57826040517f015be56a000000000000000000000000000000000000000000000000000000008152600401612f139190613833565b60405180910390fd5b50505050565b606060008203612f69576040518060400160405280600181526020017f3000000000000000000000000000000000000000000000000000000000000000815250905061307d565b600082905060005b60008214612f9b578080612f8490614126565b915050600a82612f949190614afe565b9150612f71565b60008167ffffffffffffffff811115612fb757612fb661396e565b5b6040519080825280601f01601f191660200182016040528015612fe95781602001600182028036833780820191505090505b5090505b600085146130765760018261300291906142c6565b9150600a856130119190614b2f565b603061301d919061416e565b60f81b81838151811061303357613032614b60565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a8561306f9190614afe565b9450612fed565b8093505050505b919050565b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b8060078190555050565b60006003600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060018211613184576001613192565b60018261319191906142c6565b5b905060006001836131a3919061416e565b9050600083831080156131bb57506131ba83612798565b5b80156132265750600073ffffffffffffffffffffffffffffffffffffffff166005600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b9050600061323383612798565b801561329e5750600073ffffffffffffffffffffffffffffffffffffffff166005600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b905081156132f957866005600086815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b801561335257866005600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b856005600087815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550848673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050505050565b60008082905060005b84518110156134535761343e8286838151811061343157613430614b60565b5b60200260200101516135cc565b9150808061344b90614126565b915050613411565b508091505092915050565b600080843b905060008111156135be578473ffffffffffffffffffffffffffffffffffffffff1663150b7a02338887876040518563ffffffff1660e01b81526004016134ad9493929190614be4565b6020604051808303816000875af19250505080156134e957506040513d601f19601f820116820180604052508101906134e69190614c45565b60015b61356d573d8060008114613519576040519150601f19603f3d011682016040523d82523d6000602084013e61351e565b606091505b50600081510361356557856040517f015be56a00000000000000000000000000000000000000000000000000000000815260040161355c9190613833565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614925050506135c4565b60019150505b949350505050565b60008183106135e4576135df82846135f7565b6135ef565b6135ee83836135f7565b5b905092915050565b600082600052816020526040600020905092915050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61365781613622565b811461366257600080fd5b50565b6000813590506136748161364e565b92915050565b6000602082840312156136905761368f613618565b5b600061369e84828501613665565b91505092915050565b60008115159050919050565b6136bc816136a7565b82525050565b60006020820190506136d760008301846136b3565b92915050565b6000819050919050565b6136f0816136dd565b81146136fb57600080fd5b50565b60008135905061370d816136e7565b92915050565b60006020828403121561372957613728613618565b5b6000613737848285016136fe565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561377a57808201518184015260208101905061375f565b60008484015250505050565b6000601f19601f8301169050919050565b60006137a282613740565b6137ac818561374b565b93506137bc81856020860161375c565b6137c581613786565b840191505092915050565b600060208201905081810360008301526137ea8184613797565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061381d826137f2565b9050919050565b61382d81613812565b82525050565b60006020820190506138486000830184613824565b92915050565b61385781613812565b811461386257600080fd5b50565b6000813590506138748161384e565b92915050565b6000806040838503121561389157613890613618565b5b600061389f85828601613865565b92505060206138b0858286016136fe565b9150509250929050565b6138c3816136dd565b82525050565b60006020820190506138de60008301846138ba565b92915050565b6000806000606084860312156138fd576138fc613618565b5b600061390b86828701613865565b935050602061391c86828701613865565b925050604061392d868287016136fe565b9150509250925092565b60006020828403121561394d5761394c613618565b5b600061395b84828501613865565b91505092915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6139a682613786565b810181811067ffffffffffffffff821117156139c5576139c461396e565b5b80604052505050565b60006139d861360e565b90506139e4828261399d565b919050565b600067ffffffffffffffff821115613a0457613a0361396e565b5b613a0d82613786565b9050602081019050919050565b82818337600083830152505050565b6000613a3c613a37846139e9565b6139ce565b905082815260208101848484011115613a5857613a57613969565b5b613a63848285613a1a565b509392505050565b600082601f830112613a8057613a7f613964565b5b8135613a90848260208601613a29565b91505092915050565b600060208284031215613aaf57613aae613618565b5b600082013567ffffffffffffffff811115613acd57613acc61361d565b5b613ad984828501613a6b565b91505092915050565b60038110613aef57600080fd5b50565b600081359050613b0181613ae2565b92915050565b600060208284031215613b1d57613b1c613618565b5b6000613b2b84828501613af2565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110613b7457613b73613b34565b5b50565b6000819050613b8582613b63565b919050565b6000613b9582613b77565b9050919050565b613ba581613b8a565b82525050565b6000602082019050613bc06000830184613b9c565b92915050565b600067ffffffffffffffff821115613be157613be061396e565b5b602082029050602081019050919050565b600080fd5b6000819050919050565b613c0a81613bf7565b8114613c1557600080fd5b50565b600081359050613c2781613c01565b92915050565b6000613c40613c3b84613bc6565b6139ce565b90508083825260208201905060208402830185811115613c6357613c62613bf2565b5b835b81811015613c8c5780613c788882613c18565b845260208401935050602081019050613c65565b5050509392505050565b600082601f830112613cab57613caa613964565b5b8135613cbb848260208601613c2d565b91505092915050565b600080600060608486031215613cdd57613cdc613618565b5b6000613ceb86828701613865565b935050602084013567ffffffffffffffff811115613d0c57613d0b61361d565b5b613d1886828701613c96565b9250506040613d29868287016136fe565b9150509250925092565b613d3c816136a7565b8114613d4757600080fd5b50565b600081359050613d5981613d33565b92915050565b60008060408385031215613d7657613d75613618565b5b6000613d8485828601613865565b9250506020613d9585828601613d4a565b9150509250929050565b60008060408385031215613db657613db5613618565b5b600083013567ffffffffffffffff811115613dd457613dd361361d565b5b613de085828601613c96565b9250506020613df1858286016136fe565b9150509250929050565b600067ffffffffffffffff821115613e1657613e1561396e565b5b613e1f82613786565b9050602081019050919050565b6000613e3f613e3a84613dfb565b6139ce565b905082815260208101848484011115613e5b57613e5a613969565b5b613e66848285613a1a565b509392505050565b600082601f830112613e8357613e82613964565b5b8135613e93848260208601613e2c565b91505092915050565b60008060008060808587031215613eb657613eb5613618565b5b6000613ec487828801613865565b9450506020613ed587828801613865565b9350506040613ee6878288016136fe565b925050606085013567ffffffffffffffff811115613f0757613f0661361d565b5b613f1387828801613e6e565b91505092959194509250565b60008060408385031215613f3657613f35613618565b5b6000613f44858286016136fe565b9250506020613f5585828601613865565b9150509250929050565b60008060408385031215613f7657613f75613618565b5b6000613f8485828601613865565b9250506020613f9585828601613865565b9150509250929050565b600060208284031215613fb557613fb4613618565b5b6000613fc384828501613c18565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061401357607f821691505b60208210810361402657614025613fcc565b5b50919050565b60006060820190506140416000830186613824565b61404e6020830185613824565b61405b60408301846138ba565b949350505050565b60006040820190506140786000830185613824565b6140856020830184613824565b9392505050565b60008151905061409b81613d33565b92915050565b6000602082840312156140b7576140b6613618565b5b60006140c58482850161408c565b91505092915050565b60006040820190506140e36000830185613824565b6140f060208301846138ba565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614131826136dd565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614163576141626140f7565b5b600182019050919050565b6000614179826136dd565b9150614184836136dd565b925082820190508082111561419c5761419b6140f7565b5b92915050565b7f4d617820737570706c792073686f756c6420626520677265617465722074686160008201527f6e2063757272656e7420737570706c7900000000000000000000000000000000602082015250565b60006141fe60308361374b565b9150614209826141a2565b604082019050919050565b6000602082019050818103600083015261422d816141f1565b9050919050565b7f4d617820737570706c792073686f756c6420626520677265617465722074686160008201527f6e2070726576696f7573206d617820737570706c790000000000000000000000602082015250565b600061429060358361374b565b915061429b82614234565b604082019050919050565b600060208201905081810360008301526142bf81614283565b9050919050565b60006142d1826136dd565b91506142dc836136dd565b92508282039050818111156142f4576142f36140f7565b5b92915050565b7f4e6f20736d61727420636f6e7472616374732061726520616c6c6f7765640000600082015250565b6000614330601e8361374b565b915061433b826142fa565b602082019050919050565b6000602082019050818103600083015261435f81614323565b9050919050565b7f53616c65206e6f74206163746976650000000000000000000000000000000000600082015250565b600061439c600f8361374b565b91506143a782614366565b602082019050919050565b600060208201905081810360008301526143cb8161438f565b9050919050565b7f4578636565647320737570706c79000000000000000000000000000000000000600082015250565b6000614408600e8361374b565b9150614413826143d2565b602082019050919050565b60006020820190508181036000830152614437816143fb565b9050919050565b6000614449826136dd565b9150614454836136dd565b9250828202614462816136dd565b91508282048414831517614479576144786140f7565b5b5092915050565b7f45746865722073656e74206973206e6f7420636f727265637400000000000000600082015250565b60006144b660198361374b565b91506144c182614480565b602082019050919050565b600060208201905081810360008301526144e5816144a9565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b6000815461451981613ffb565b61452381866144ec565b9450600182166000811461453e576001811461455357614586565b60ff1983168652811515820286019350614586565b61455c856144f7565b60005b8381101561457e5781548189015260018201915060208101905061455f565b838801955050505b50505092915050565b600061459a82613740565b6145a481856144ec565b93506145b481856020860161375c565b80840191505092915050565b60006145cc828561450c565b91506145d8828461458f565b91508190509392505050565b7f45786365656473206d696e74207065722077616c6c6574000000000000000000600082015250565b600061461a60178361374b565b9150614625826145e4565b602082019050919050565b600060208201905081810360008301526146498161460d565b9050919050565b7f4e6f2062616c616e636520746f20776974686472617700000000000000000000600082015250565b600061468660168361374b565b915061469182614650565b602082019050919050565b600060208201905081810360008301526146b581614679565b9050919050565b7f416d6f756e74206973206e6f742076616c696400000000000000000000000000600082015250565b60006146f260138361374b565b91506146fd826146bc565b602082019050919050565b60006020820190508181036000830152614721816146e5565b9050919050565b600081905092915050565b50565b6000614743600083614728565b915061474e82614733565b600082019050919050565b600061476482614736565b9150819050919050565b7f5472616e73616374696f6e206661696c65640000000000000000000000000000600082015250565b60006147a460128361374b565b91506147af8261476e565b602082019050919050565b600060208201905081810360008301526147d381614797565b9050919050565b60006147e5826136dd565b9150600082036147f8576147f76140f7565b5b600182039050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026148507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614813565b61485a8683614813565b95508019841693508086168417925050509392505050565b6000819050919050565b600061489761489261488d846136dd565b614872565b6136dd565b9050919050565b6000819050919050565b6148b18361487c565b6148c56148bd8261489e565b848454614820565b825550505050565b600090565b6148da6148cd565b6148e58184846148a8565b505050565b5b81811015614909576148fe6000826148d2565b6001810190506148eb565b5050565b601f82111561494e5761491f816144f7565b61492884614803565b81016020851015614937578190505b61494b61494385614803565b8301826148ea565b50505b505050565b600082821c905092915050565b600061497160001984600802614953565b1980831691505092915050565b600061498a8383614960565b9150826002028217905092915050565b6149a382613740565b67ffffffffffffffff8111156149bc576149bb61396e565b5b6149c68254613ffb565b6149d182828561490d565b600060209050601f831160018114614a0457600084156149f2578287015190505b6149fc858261497e565b865550614a64565b601f198416614a12866144f7565b60005b82811015614a3a57848901518255600182019150602085019450602081019050614a15565b86831015614a575784890151614a53601f891682614960565b8355505b6001600288020188555050505b505050505050565b60008160601b9050919050565b6000614a8482614a6c565b9050919050565b6000614a9682614a79565b9050919050565b614aae614aa982613812565b614a8b565b82525050565b6000614ac08284614a9d565b60148201915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614b09826136dd565b9150614b14836136dd565b925082614b2457614b23614acf565b5b828204905092915050565b6000614b3a826136dd565b9150614b45836136dd565b925082614b5557614b54614acf565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050919050565b600082825260208201905092915050565b6000614bb682614b8f565b614bc08185614b9a565b9350614bd081856020860161375c565b614bd981613786565b840191505092915050565b6000608082019050614bf96000830187613824565b614c066020830186613824565b614c1360408301856138ba565b8181036060830152614c258184614bab565b905095945050505050565b600081519050614c3f8161364e565b92915050565b600060208284031215614c5b57614c5a613618565b5b6000614c6984828501614c30565b9150509291505056fea2646970667358221220f421f832a83304ef944ee0444694434aa2fe84d630e552f4a840794ae955487b64736f6c63430008110033

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

000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000d536176616765204e6174696f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d536176616765204e6174696f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005868747470733a2f2f7361766167656e6174696f6e2e6d7970696e6174612e636c6f75642f697066732f516d5833517a6e36654c35484e374548413650657475735732324455776f756d524c31444e696d315153745147482f0000000000000000

-----Decoded View---------------
Arg [0] : name_ (string): Savage Nation
Arg [1] : symbol_ (string): Savage Nation
Arg [2] : baseURI_ (string): https://savagenation.mypinata.cloud/ipfs/QmX3Qzn6eL5HN7EHA6PetusW22DUwoumRL1DNim1QStQGH/

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [4] : 536176616765204e6174696f6e00000000000000000000000000000000000000
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [6] : 536176616765204e6174696f6e00000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000058
Arg [8] : 68747470733a2f2f7361766167656e6174696f6e2e6d7970696e6174612e636c
Arg [9] : 6f75642f697066732f516d5833517a6e36654c35484e37454841365065747573
Arg [10] : 5732324455776f756d524c31444e696d315153745147482f0000000000000000


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.