ETH Price: $3,184.45 (+0.95%)
Gas: 4 Gwei

Contract

0x61E3D1C26802DF805e9Fc22Dc26342e29eCFe860
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Approval For...202913922024-07-12 15:42:5946 hrs ago1720798979IN
Savage Nation: Savage Nation Token
0 ETH0.000281236.03314313
Set Approval For...202745632024-07-10 7:19:594 days ago1720595999IN
Savage Nation: Savage Nation Token
0 ETH0.000230924.95396051
Set Approval For...202645052024-07-08 21:36:595 days ago1720474619IN
Savage Nation: Savage Nation Token
0 ETH0.00013522.89533862
Transfer From202606492024-07-08 8:37:476 days ago1720427867IN
Savage Nation: Savage Nation Token
0 ETH0.000261246.04716903
Set Approval For...202600432024-07-08 6:35:596 days ago1720420559IN
Savage Nation: Savage Nation Token
0 ETH0.000152933.28083918
Set Approval For...202474912024-07-06 12:33:478 days ago1720269227IN
Savage Nation: Savage Nation Token
0 ETH0.000090991.95201107
Set Approval For...202470672024-07-06 11:08:118 days ago1720264091IN
Savage Nation: Savage Nation Token
0 ETH0.000111922.4011523
Set Approval For...202449892024-07-06 4:08:598 days ago1720238939IN
Savage Nation: Savage Nation Token
0 ETH0.000094862.03512671
Set Approval For...202449882024-07-06 4:08:478 days ago1720238927IN
Savage Nation: Savage Nation Token
0 ETH0.000095262.04006256
Set Approval For...202449872024-07-06 4:08:358 days ago1720238915IN
Savage Nation: Savage Nation Token
0 ETH0.000079461.70480333
Safe Transfer Fr...202448432024-07-06 3:39:478 days ago1720237187IN
Savage Nation: Savage Nation Token
0 ETH0.000527831.7622567
Set Approval For...202267352024-07-03 14:59:4710 days ago1720018787IN
Savage Nation: Savage Nation Token
0 ETH0.000608113.04518362
Set Approval For...202258412024-07-03 11:59:4711 days ago1720007987IN
Savage Nation: Savage Nation Token
0 ETH0.000230844.95222434
Set Approval For...202243372024-07-03 6:57:2311 days ago1719989843IN
Savage Nation: Savage Nation Token
0 ETH0.0001372.93454356
Set Approval For...202157272024-07-02 2:03:2312 days ago1719885803IN
Savage Nation: Savage Nation Token
0 ETH0.00007381.58047511
Safe Transfer Fr...202084282024-07-01 1:36:3513 days ago1719797795IN
Savage Nation: Savage Nation Token
0 ETH0.000211784.55421425
Set Approval For...202040562024-06-30 10:58:3514 days ago1719745115IN
Savage Nation: Savage Nation Token
0 ETH0.000097242.08616225
Set Approval For...201878892024-06-28 4:46:5916 days ago1719550019IN
Savage Nation: Savage Nation Token
0 ETH0.000078042.92151773
Set Approval For...201878892024-06-28 4:46:5916 days ago1719550019IN
Savage Nation: Savage Nation Token
0 ETH0.000125052.68265118
Set Approval For...201566992024-06-23 20:12:5920 days ago1719173579IN
Savage Nation: Savage Nation Token
0 ETH0.000053652.0083744
Set Approval For...201566942024-06-23 20:11:5920 days ago1719173519IN
Savage Nation: Savage Nation Token
0 ETH0.000083631.79414426
Safe Transfer Fr...201417852024-06-21 18:07:3522 days ago1718993255IN
Savage Nation: Savage Nation Token
0 ETH0.00028956.2343197
Safe Transfer Fr...201417832024-06-21 18:07:1122 days ago1718993231IN
Savage Nation: Savage Nation Token
0 ETH0.000257125.53703693
Safe Transfer Fr...201417822024-06-21 18:06:5922 days ago1718993219IN
Savage Nation: Savage Nation Token
0 ETH0.000256785.52961955
Set Approval For...200986162024-06-15 17:14:3528 days ago1718471675IN
Savage Nation: Savage Nation Token
0 ETH0.000160086.48029963
View all transactions

Latest 10 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
162303132022-12-21 3:13:11571 days ago1671592391
Savage Nation: Savage Nation Token
1.983 ETH
162303082022-12-21 3:12:11571 days ago1671592331
Savage Nation: Savage Nation Token
30 ETH
162303002022-12-21 3:10:23571 days ago1671592223
Savage Nation: Savage Nation Token
25 ETH
162302892022-12-21 3:08:11571 days ago1671592091
Savage Nation: Savage Nation Token
30 ETH
162302862022-12-21 3:07:35571 days ago1671592055
Savage Nation: Savage Nation Token
30 ETH
162302822022-12-21 3:06:47571 days ago1671592007
Savage Nation: Savage Nation Token
10 ETH
162302782022-12-21 3:05:59571 days ago1671591959
Savage Nation: Savage Nation Token
5 ETH
161992882022-12-16 19:16:11575 days ago1671218171
Savage Nation: Savage Nation Token
0.118 ETH
161992172022-12-16 19:01:47575 days ago1671217307
Savage Nation: Savage Nation Token
0.118 ETH
161991852022-12-16 18:55:23575 days ago1671216923
Savage Nation: Savage Nation Token
0.078 ETH
Loading...
Loading

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

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

Validator Index Block Amount
View All Withdrawals

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

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