ETH Price: $3,151.30 (+2.91%)

Token

LightTrails (LTTrail)
 

Overview

Max Total Supply

1,000 LTTrail

Holders

753

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
irbis.eth
Balance
26 LTTrail
0x78805dd0a19ac89af3cc334c79330e6ad9cdaf0c
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
LightTrails

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-12-22
*/

// SPDX-License-Identifier: MIT
// File: IOperatorFilterRegistry.sol


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 unregister(address addr) 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: OperatorFilterer.sol


pragma solidity ^0.8.13;


/**
 * @title  OperatorFilterer
 * @notice Abstract contract whose constructor automatically registers and optionally subscribes to or copies another
 *         registrant's entries in the OperatorFilterRegistry.
 */
abstract contract OperatorFilterer {
    error OperatorNotAllowed(address operator);

    IOperatorFilterRegistry constant OPERATOR_FILTER_REGISTRY =
        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(OPERATOR_FILTER_REGISTRY).code.length > 0) {
            if (subscribe) {
                OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
            } else {
                if (subscriptionOrRegistrantToCopy != address(0)) {
                    OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
                } else {
                    OPERATOR_FILTER_REGISTRY.register(address(this));
                }
            }
        }
    }

    modifier onlyAllowedOperator(address from) virtual {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (address(OPERATOR_FILTER_REGISTRY).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 (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), msg.sender)) {
                revert OperatorNotAllowed(msg.sender);
            }
        }
        _;
    }

    modifier onlyAllowedOperatorApproval(address operator) virtual {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
            if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) {
                revert OperatorNotAllowed(operator);
            }
        }
        _;
    }
}

// File: DefaultOperatorFilterer.sol


pragma solidity ^0.8.13;


/**
 * @title  DefaultOperatorFilterer
 * @notice Inherits from OperatorFilterer and automatically subscribes to the default OpenSea subscription.
 */
abstract contract DefaultOperatorFilterer is OperatorFilterer {
    address constant DEFAULT_SUBSCRIPTION = address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6);

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

// File: whitelist_flat.sol

// File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)


pragma solidity ^0.8.4;

/**
 * @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: https://github.com/chiru-labs/ERC721A/blob/main/contracts/IERC721A.sol


// ERC721A Contracts v4.2.2
// Creator: Chiru Labs

pragma solidity ^0.8.4;

/**
 * @dev Interface of ERC721A.
 */
interface IERC721A {
    /**
     * The caller must own the token or be an approved operator.
     */
    error ApprovalCallerNotOwnerNorApproved();

    /**
     * The token does not exist.
     */
    error ApprovalQueryForNonexistentToken();

    /**
     * Cannot query the balance for the zero address.
     */
    error BalanceQueryForZeroAddress();

    /**
     * Cannot mint to the zero address.
     */
    error MintToZeroAddress();

    /**
     * The quantity of tokens minted must be more than zero.
     */
    error MintZeroQuantity();

    /**
     * The token does not exist.
     */
    error OwnerQueryForNonexistentToken();

    /**
     * The caller must own the token or be an approved operator.
     */
    error TransferCallerNotOwnerNorApproved();

    /**
     * The token must be owned by `from`.
     */
    error TransferFromIncorrectOwner();

    /**
     * Cannot safely transfer to a contract that does not implement the
     * ERC721Receiver interface.
     */
    error TransferToNonERC721ReceiverImplementer();

    /**
     * Cannot transfer to the zero address.
     */
    error TransferToZeroAddress();

    /**
     * The token does not exist.
     */
    error URIQueryForNonexistentToken();

    /**
     * The `quantity` minted with ERC2309 exceeds the safety limit.
     */
    error MintERC2309QuantityExceedsLimit();

    /**
     * The `extraData` cannot be set on an unintialized ownership slot.
     */
    error OwnershipNotInitializedForExtraData();

    // =============================================================
    //                            STRUCTS
    // =============================================================

    struct TokenOwnership {
        // The address of the owner.
        address addr;
        // Stores the start time of ownership with minimal overhead for tokenomics.
        uint64 startTimestamp;
        // Whether the token has been burned.
        bool burned;
        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
        uint24 extraData;
    }

    // =============================================================
    //                         TOKEN COUNTERS
    // =============================================================

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() external view returns (uint256);

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    // =============================================================
    //                            IERC721
    // =============================================================

    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

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

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

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

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

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

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom}
     * whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token
     * by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

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

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

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

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

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

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

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

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

    // =============================================================
    //                           IERC2309
    // =============================================================

    /**
     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
     * (inclusive) is transferred from `from` to `to`, as defined in the
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
     *
     * See {_mintERC2309} for more details.
     */
    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}

// File: https://github.com/chiru-labs/ERC721A/blob/main/contracts/ERC721A.sol


// ERC721A Contracts v4.2.2
// Creator: Chiru Labs

pragma solidity ^0.8.4;


/**
 * @dev Interface of ERC721 token receiver.
 */
interface ERC721A__IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

/**
 * @title ERC721A
 *
 * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
 * Non-Fungible Token Standard, including the Metadata extension.
 * Optimized for lower gas during batch mints.
 *
 * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
 * starting from `_startTokenId()`.
 *
 * Assumptions:
 *
 * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
 * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
 */
contract ERC721A is IERC721A {
    // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
    struct TokenApprovalRef {
        address value;
    }

    // =============================================================
    //                           CONSTANTS
    // =============================================================

    // Mask of an entry in packed address data.
    uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;

    // The bit position of `numberMinted` in packed address data.
    uint256 private constant _BITPOS_NUMBER_MINTED = 64;

    // The bit position of `numberBurned` in packed address data.
    uint256 private constant _BITPOS_NUMBER_BURNED = 128;

    // The bit position of `aux` in packed address data.
    uint256 private constant _BITPOS_AUX = 192;

    // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
    uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;

    // The bit position of `startTimestamp` in packed ownership.
    uint256 private constant _BITPOS_START_TIMESTAMP = 160;

    // The bit mask of the `burned` bit in packed ownership.
    uint256 private constant _BITMASK_BURNED = 1 << 224;

    // The bit position of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;

    // The bit mask of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;

    // The bit position of `extraData` in packed ownership.
    uint256 private constant _BITPOS_EXTRA_DATA = 232;

    // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
    uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;

    // The mask of the lower 160 bits for addresses.
    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;

    // The maximum `quantity` that can be minted with {_mintERC2309}.
    // This limit is to prevent overflows on the address data entries.
    // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
    // is required to cause an overflow, which is unrealistic.
    uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;

    // The `Transfer` event signature is given by:
    // `keccak256(bytes("Transfer(address,address,uint256)"))`.
    bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    // =============================================================
    //                            STORAGE
    // =============================================================

    // The next token ID to be minted.
    uint256 private _currentIndex;

    // The number of tokens burned.
    uint256 private _burnCounter;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to ownership details
    // An empty struct value does not necessarily mean the token is unowned.
    // See {_packedOwnershipOf} implementation for details.
    //
    // Bits Layout:
    // - [0..159]   `addr`
    // - [160..223] `startTimestamp`
    // - [224]      `burned`
    // - [225]      `nextInitialized`
    // - [232..255] `extraData`
    mapping(uint256 => uint256) private _packedOwnerships;

    // Mapping owner address to address data.
    //
    // Bits Layout:
    // - [0..63]    `balance`
    // - [64..127]  `numberMinted`
    // - [128..191] `numberBurned`
    // - [192..255] `aux`
    mapping(address => uint256) private _packedAddressData;

    // Mapping from token ID to approved address.
    mapping(uint256 => TokenApprovalRef) private _tokenApprovals;

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

    // =============================================================
    //                          CONSTRUCTOR
    // =============================================================

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _currentIndex = _startTokenId();
    }

    // =============================================================
    //                   TOKEN COUNTING OPERATIONS
    // =============================================================

    /**
     * @dev Returns the starting token ID.
     * To change the starting token ID, please override this function.
     */
    function _startTokenId() internal view virtual returns (uint256) {
        return 0;
    }

    /**
     * @dev Returns the next token ID to be minted.
     */
    function _nextTokenId() internal view virtual returns (uint256) {
        return _currentIndex;
    }

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        // Counter underflow is impossible as _burnCounter cannot be incremented
        // more than `_currentIndex - _startTokenId()` times.
        unchecked {
            return _currentIndex - _burnCounter - _startTokenId();
        }
    }

    /**
     * @dev Returns the total amount of tokens minted in the contract.
     */
    function _totalMinted() internal view virtual returns (uint256) {
        // Counter underflow is impossible as `_currentIndex` does not decrement,
        // and it is initialized to `_startTokenId()`.
        unchecked {
            return _currentIndex - _startTokenId();
        }
    }

    /**
     * @dev Returns the total number of tokens burned.
     */
    function _totalBurned() internal view virtual returns (uint256) {
        return _burnCounter;
    }

    // =============================================================
    //                    ADDRESS DATA OPERATIONS
    // =============================================================

    /**
     * @dev Returns the number of tokens in `owner`'s account.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        if (owner == address(0)) revert BalanceQueryForZeroAddress();
        return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens minted by `owner`.
     */
    function _numberMinted(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens burned by or on behalf of `owner`.
     */
    function _numberBurned(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     */
    function _getAux(address owner) internal view returns (uint64) {
        return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
    }

    /**
     * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     * If there are multiple variables, please pack them into a uint64.
     */
    function _setAux(address owner, uint64 aux) internal virtual {
        uint256 packed = _packedAddressData[owner];
        uint256 auxCasted;
        // Cast `aux` with assembly to avoid redundant masking.
        assembly {
            auxCasted := aux
        }
        packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
        _packedAddressData[owner] = packed;
    }

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        // The interface IDs are constants representing the first 4 bytes
        // of the XOR of all function selectors in the interface.
        // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
        // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
        return
            interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
            interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
            interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
    }

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

    /**
     * @dev Returns the token collection name.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        if (!_exists(tokenId)) revert URIQueryForNonexistentToken();

        string memory baseURI = _baseURI();
        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
    }

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

    // =============================================================
    //                     OWNERSHIPS OPERATIONS
    // =============================================================

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

    /**
     * @dev Gas spent here starts off proportional to the maximum mint batch size.
     * It gradually moves to O(1) as tokens get transferred around over time.
     */
    function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnershipOf(tokenId));
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct at `index`.
     */
    function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnerships[index]);
    }

    /**
     * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
     */
    function _initializeOwnershipAt(uint256 index) internal virtual {
        if (_packedOwnerships[index] == 0) {
            _packedOwnerships[index] = _packedOwnershipOf(index);
        }
    }

    /**
     * Returns the packed ownership data of `tokenId`.
     */
    function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
        uint256 curr = tokenId;

        unchecked {
            if (_startTokenId() <= curr)
                if (curr < _currentIndex) {
                    uint256 packed = _packedOwnerships[curr];
                    // If not burned.
                    if (packed & _BITMASK_BURNED == 0) {
                        // Invariant:
                        // There will always be an initialized ownership slot
                        // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                        // before an unintialized ownership slot
                        // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                        // Hence, `curr` will not underflow.
                        //
                        // We can directly compare the packed value.
                        // If the address is zero, packed will be zero.
                        while (packed == 0) {
                            packed = _packedOwnerships[--curr];
                        }
                        return packed;
                    }
                }
        }
        revert OwnerQueryForNonexistentToken();
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
     */
    function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
        ownership.addr = address(uint160(packed));
        ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
        ownership.burned = packed & _BITMASK_BURNED != 0;
        ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
    }

    /**
     * @dev Packs ownership data into a single uint256.
     */
    function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
            result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
        }
    }

    /**
     * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
     */
    function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
        // For branchless setting of the `nextInitialized` flag.
        assembly {
            // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
            result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
        }
    }

    // =============================================================
    //                      APPROVAL OPERATIONS
    // =============================================================

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

        if (_msgSenderERC721A() != owner)
            if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                revert ApprovalCallerNotOwnerNorApproved();
            }

        _tokenApprovals[tokenId].value = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();

        return _tokenApprovals[tokenId].value;
    }

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

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

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted. See {_mint}.
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return
            _startTokenId() <= tokenId &&
            tokenId < _currentIndex && // If within bounds,
            _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
    }

    /**
     * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
     */
    function _isSenderApprovedOrOwner(
        address approvedAddress,
        address owner,
        address msgSender
    ) private pure returns (bool result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
            msgSender := and(msgSender, _BITMASK_ADDRESS)
            // `msgSender == owner || msgSender == approvedAddress`.
            result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
        }
    }

    /**
     * @dev Returns the storage slot and value for the approved address of `tokenId`.
     */
    function _getApprovedSlotAndAddress(uint256 tokenId)
        private
        view
        returns (uint256 approvedAddressSlot, address approvedAddress)
    {
        TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
        // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
        assembly {
            approvedAddressSlot := tokenApproval.slot
            approvedAddress := sload(approvedAddressSlot)
        }
    }

    // =============================================================
    //                      TRANSFER OPERATIONS
    // =============================================================

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token
     * by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);

        if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        // The nested ifs save around 20+ gas over a compound boolean condition.
        if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
            if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();

        if (to == address(0)) revert TransferToZeroAddress();

        _beforeTokenTransfers(from, to, tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // We can directly increment and decrement the balances.
            --_packedAddressData[from]; // Updates: `balance -= 1`.
            ++_packedAddressData[to]; // Updates: `balance += 1`.

            // Updates:
            // - `address` to the next owner.
            // - `startTimestamp` to the timestamp of transfering.
            // - `burned` to `false`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                to,
                _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, to, tokenId);
        _afterTokenTransfers(from, to, tokenId, 1);
    }

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, '');
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token
     * by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement
     * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public virtual override {
        transferFrom(from, to, tokenId);
        if (to.code.length != 0)
            if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                revert TransferToNonERC721ReceiverImplementer();
            }
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token IDs
     * are about to be transferred. This includes minting.
     * And also called before burning one token.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Hook that is called after a set of serially-ordered token IDs
     * have been transferred. This includes minting.
     * And also called after one token has been burned.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
     * transferred to `to`.
     * - When `from` is zero, `tokenId` has been minted for `to`.
     * - When `to` is zero, `tokenId` has been burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
     *
     * `from` - Previous owner of the given token ID.
     * `to` - Target address that will receive the token.
     * `tokenId` - Token ID to be transferred.
     * `_data` - Optional data to send along with the call.
     *
     * Returns whether the call correctly returned the expected magic value.
     */
    function _checkContractOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
            bytes4 retval
        ) {
            return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
        } catch (bytes memory reason) {
            if (reason.length == 0) {
                revert TransferToNonERC721ReceiverImplementer();
            } else {
                assembly {
                    revert(add(32, reason), mload(reason))
                }
            }
        }
    }

    // =============================================================
    //                        MINT OPERATIONS
    // =============================================================

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _mint(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (quantity == 0) revert MintZeroQuantity();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are incredibly unrealistic.
        // `balance` and `numberMinted` have a maximum limit of 2**64.
        // `tokenId` has a maximum limit of 2**256.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            uint256 toMasked;
            uint256 end = startTokenId + quantity;

            // Use assembly to loop and emit the `Transfer` event for gas savings.
            // The duplicated `log4` removes an extra check and reduces stack juggling.
            // The assembly, together with the surrounding Solidity code, have been
            // delicately arranged to nudge the compiler into producing optimized opcodes.
            assembly {
                // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                toMasked := and(to, _BITMASK_ADDRESS)
                // Emit the `Transfer` event.
                log4(
                    0, // Start of data (0, since no data).
                    0, // End of data (0, since no data).
                    _TRANSFER_EVENT_SIGNATURE, // Signature.
                    0, // `address(0)`.
                    toMasked, // `to`.
                    startTokenId // `tokenId`.
                )

                for {
                    let tokenId := add(startTokenId, 1)
                } iszero(eq(tokenId, end)) {
                    tokenId := add(tokenId, 1)
                } {
                    // Emit the `Transfer` event. Similar to above.
                    log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                }
            }
            if (toMasked == 0) revert MintToZeroAddress();

            _currentIndex = end;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * This function is intended for efficient minting only during contract creation.
     *
     * It emits only one {ConsecutiveTransfer} as defined in
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
     * instead of a sequence of {Transfer} event(s).
     *
     * Calling this function outside of contract creation WILL make your contract
     * non-compliant with the ERC721 standard.
     * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
     * {ConsecutiveTransfer} event is only permissible during contract creation.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {ConsecutiveTransfer} event.
     */
    function _mintERC2309(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (to == address(0)) revert MintToZeroAddress();
        if (quantity == 0) revert MintZeroQuantity();
        if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);

            _currentIndex = startTokenId + quantity;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Safely mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement
     * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
     * - `quantity` must be greater than 0.
     *
     * See {_mint}.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual {
        _mint(to, quantity);

        unchecked {
            if (to.code.length != 0) {
                uint256 end = _currentIndex;
                uint256 index = end - quantity;
                do {
                    if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
                } while (index < end);
                // Reentrancy protection.
                if (_currentIndex != end) revert();
            }
        }
    }

    /**
     * @dev Equivalent to `_safeMint(to, quantity, '')`.
     */
    function _safeMint(address to, uint256 quantity) internal virtual {
        _safeMint(to, quantity, '');
    }

    // =============================================================
    //                        BURN OPERATIONS
    // =============================================================

    /**
     * @dev Equivalent to `_burn(tokenId, false)`.
     */
    function _burn(uint256 tokenId) internal virtual {
        _burn(tokenId, false);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);

        address from = address(uint160(prevOwnershipPacked));

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        if (approvalCheck) {
            // The nested ifs save around 20+ gas over a compound boolean condition.
            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
        }

        _beforeTokenTransfers(from, address(0), tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // Updates:
            // - `balance -= 1`.
            // - `numberBurned += 1`.
            //
            // We can directly decrement the balance, and increment the number burned.
            // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
            _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;

            // Updates:
            // - `address` to the last owner.
            // - `startTimestamp` to the timestamp of burning.
            // - `burned` to `true`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                from,
                (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, address(0), tokenId);
        _afterTokenTransfers(from, address(0), tokenId, 1);

        // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
        unchecked {
            _burnCounter++;
        }
    }

    // =============================================================
    //                     EXTRA DATA OPERATIONS
    // =============================================================

    /**
     * @dev Directly sets the extra data for the ownership data `index`.
     */
    function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
        uint256 packed = _packedOwnerships[index];
        if (packed == 0) revert OwnershipNotInitializedForExtraData();
        uint256 extraDataCasted;
        // Cast `extraData` with assembly to avoid redundant masking.
        assembly {
            extraDataCasted := extraData
        }
        packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
        _packedOwnerships[index] = packed;
    }

    /**
     * @dev Called during each token transfer to set the 24bit `extraData` field.
     * Intended to be overridden by the cosumer contract.
     *
     * `previousExtraData` - the value of `extraData` before transfer.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _extraData(
        address from,
        address to,
        uint24 previousExtraData
    ) internal view virtual returns (uint24) {}

    /**
     * @dev Returns the next extra data for the packed ownership data.
     * The returned result is shifted into position.
     */
    function _nextExtraData(
        address from,
        address to,
        uint256 prevOwnershipPacked
    ) private view returns (uint256) {
        uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
        return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
    }

    // =============================================================
    //                       OTHER OPERATIONS
    // =============================================================

    /**
     * @dev Returns the message sender (defaults to `msg.sender`).
     *
     * If you are writing GSN compatible contracts, you need to override this function.
     */
    function _msgSenderERC721A() internal view virtual returns (address) {
        return msg.sender;
    }

    /**
     * @dev Converts a uint256 to its ASCII string decimal representation.
     */
    function _toString(uint256 value) internal pure virtual returns (string memory str) {
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
            let m := add(mload(0x40), 0xa0)
            // Update the free memory pointer to allocate.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                str := sub(str, 1)
                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))
                // Keep dividing `temp` until zero.
                temp := div(temp, 10)
                // prettier-ignore
                if iszero(temp) { break }
            }

            let length := sub(end, str)
            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 0x20)
            // Store the length.
            mstore(str, length)
        }
    }
}

// File: https://github.com/chiru-labs/ERC721A/blob/main/contracts/extensions/IERC721AQueryable.sol


// ERC721A Contracts v4.2.2
// Creator: Chiru Labs

pragma solidity ^0.8.4;


/**
 * @dev Interface of ERC721AQueryable.
 */
interface IERC721AQueryable is IERC721A {
    /**
     * Invalid query range (`start` >= `stop`).
     */
    error InvalidQueryRange();

    /**
     * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
     *
     * If the `tokenId` is out of bounds:
     *
     * - `addr = address(0)`
     * - `startTimestamp = 0`
     * - `burned = false`
     * - `extraData = 0`
     *
     * If the `tokenId` is burned:
     *
     * - `addr = <Address of owner before token was burned>`
     * - `startTimestamp = <Timestamp when token was burned>`
     * - `burned = true`
     * - `extraData = <Extra data when token was burned>`
     *
     * Otherwise:
     *
     * - `addr = <Address of owner>`
     * - `startTimestamp = <Timestamp of start of ownership>`
     * - `burned = false`
     * - `extraData = <Extra data at start of ownership>`
     */
    function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory);

    /**
     * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
     * See {ERC721AQueryable-explicitOwnershipOf}
     */
    function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory);

    /**
     * @dev Returns an array of token IDs owned by `owner`,
     * in the range [`start`, `stop`)
     * (i.e. `start <= tokenId < stop`).
     *
     * This function allows for tokens to be queried if the collection
     * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
     *
     * Requirements:
     *
     * - `start < stop`
     */
    function tokensOfOwnerIn(
        address owner,
        uint256 start,
        uint256 stop
    ) external view returns (uint256[] memory);

    /**
     * @dev Returns an array of token IDs owned by `owner`.
     *
     * This function scans the ownership mapping and is O(`totalSupply`) in complexity.
     * It is meant to be called off-chain.
     *
     * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
     * multiple smaller scans if the collection is large enough to cause
     * an out-of-gas error (10K collections should be fine).
     */
    function tokensOfOwner(address owner) external view returns (uint256[] memory);
}

// File: https://github.com/chiru-labs/ERC721A/blob/main/contracts/extensions/ERC721AQueryable.sol


// ERC721A Contracts v4.2.2
// Creator: Chiru Labs

pragma solidity ^0.8.4;



/**
 * @title ERC721AQueryable.
 *
 * @dev ERC721A subclass with convenience query functions.
 */
abstract contract ERC721AQueryable is ERC721A, IERC721AQueryable {
    /**
     * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
     *
     * If the `tokenId` is out of bounds:
     *
     * - `addr = address(0)`
     * - `startTimestamp = 0`
     * - `burned = false`
     * - `extraData = 0`
     *
     * If the `tokenId` is burned:
     *
     * - `addr = <Address of owner before token was burned>`
     * - `startTimestamp = <Timestamp when token was burned>`
     * - `burned = true`
     * - `extraData = <Extra data when token was burned>`
     *
     * Otherwise:
     *
     * - `addr = <Address of owner>`
     * - `startTimestamp = <Timestamp of start of ownership>`
     * - `burned = false`
     * - `extraData = <Extra data at start of ownership>`
     */
    function explicitOwnershipOf(uint256 tokenId) public view virtual override returns (TokenOwnership memory) {
        TokenOwnership memory ownership;
        if (tokenId < _startTokenId() || tokenId >= _nextTokenId()) {
            return ownership;
        }
        ownership = _ownershipAt(tokenId);
        if (ownership.burned) {
            return ownership;
        }
        return _ownershipOf(tokenId);
    }

    /**
     * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
     * See {ERC721AQueryable-explicitOwnershipOf}
     */
    function explicitOwnershipsOf(uint256[] calldata tokenIds)
        external
        view
        virtual
        override
        returns (TokenOwnership[] memory)
    {
        unchecked {
            uint256 tokenIdsLength = tokenIds.length;
            TokenOwnership[] memory ownerships = new TokenOwnership[](tokenIdsLength);
            for (uint256 i; i != tokenIdsLength; ++i) {
                ownerships[i] = explicitOwnershipOf(tokenIds[i]);
            }
            return ownerships;
        }
    }

    /**
     * @dev Returns an array of token IDs owned by `owner`,
     * in the range [`start`, `stop`)
     * (i.e. `start <= tokenId < stop`).
     *
     * This function allows for tokens to be queried if the collection
     * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
     *
     * Requirements:
     *
     * - `start < stop`
     */
    function tokensOfOwnerIn(
        address owner,
        uint256 start,
        uint256 stop
    ) external view virtual override returns (uint256[] memory) {
        unchecked {
            if (start >= stop) revert InvalidQueryRange();
            uint256 tokenIdsIdx;
            uint256 stopLimit = _nextTokenId();
            // Set `start = max(start, _startTokenId())`.
            if (start < _startTokenId()) {
                start = _startTokenId();
            }
            // Set `stop = min(stop, stopLimit)`.
            if (stop > stopLimit) {
                stop = stopLimit;
            }
            uint256 tokenIdsMaxLength = balanceOf(owner);
            // Set `tokenIdsMaxLength = min(balanceOf(owner), stop - start)`,
            // to cater for cases where `balanceOf(owner)` is too big.
            if (start < stop) {
                uint256 rangeLength = stop - start;
                if (rangeLength < tokenIdsMaxLength) {
                    tokenIdsMaxLength = rangeLength;
                }
            } else {
                tokenIdsMaxLength = 0;
            }
            uint256[] memory tokenIds = new uint256[](tokenIdsMaxLength);
            if (tokenIdsMaxLength == 0) {
                return tokenIds;
            }
            // We need to call `explicitOwnershipOf(start)`,
            // because the slot at `start` may not be initialized.
            TokenOwnership memory ownership = explicitOwnershipOf(start);
            address currOwnershipAddr;
            // If the starting slot exists (i.e. not burned), initialize `currOwnershipAddr`.
            // `ownership.address` will not be zero, as `start` is clamped to the valid token ID range.
            if (!ownership.burned) {
                currOwnershipAddr = ownership.addr;
            }
            for (uint256 i = start; i != stop && tokenIdsIdx != tokenIdsMaxLength; ++i) {
                ownership = _ownershipAt(i);
                if (ownership.burned) {
                    continue;
                }
                if (ownership.addr != address(0)) {
                    currOwnershipAddr = ownership.addr;
                }
                if (currOwnershipAddr == owner) {
                    tokenIds[tokenIdsIdx++] = i;
                }
            }
            // Downsize the array to fit.
            assembly {
                mstore(tokenIds, tokenIdsIdx)
            }
            return tokenIds;
        }
    }

    /**
     * @dev Returns an array of token IDs owned by `owner`.
     *
     * This function scans the ownership mapping and is O(`totalSupply`) in complexity.
     * It is meant to be called off-chain.
     *
     * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
     * multiple smaller scans if the collection is large enough to cause
     * an out-of-gas error (10K collections should be fine).
     */
    function tokensOfOwner(address owner) external view virtual override returns (uint256[] memory) {
        unchecked {
            uint256 tokenIdsIdx;
            address currOwnershipAddr;
            uint256 tokenIdsLength = balanceOf(owner);
            uint256[] memory tokenIds = new uint256[](tokenIdsLength);
            TokenOwnership memory ownership;
            for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) {
                ownership = _ownershipAt(i);
                if (ownership.burned) {
                    continue;
                }
                if (ownership.addr != address(0)) {
                    currOwnershipAddr = ownership.addr;
                }
                if (currOwnershipAddr == owner) {
                    tokenIds[tokenIdsIdx++] = i;
                }
            }
            return tokenIds;
        }
    }
}

// File: https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol


pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnerUpdated(address indexed user, address indexed newOwner);

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnerUpdated(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function setOwner(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnerUpdated(msg.sender, newOwner);
    }
}

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol


// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

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

    /**
     * @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 Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

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

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

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol


// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - 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
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721Receiver.sol


// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

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

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/ERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;


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

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721.sol


// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;


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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

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

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

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

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

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/extensions/IERC721Metadata.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;


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

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

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

// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol


// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)

pragma solidity ^0.8.0;








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

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

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

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

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

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: address zero is not a valid owner");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: invalid token ID");
        return owner;
    }

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

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

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

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

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

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not token owner or approved for all"
        );

        _approve(to, tokenId);
    }

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

        return _tokenApprovals[tokenId];
    }

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

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

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");

        _transfer(from, to, tokenId);
    }

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

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
        _safeTransfer(from, to, tokenId, data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

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

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        // Check that tokenId was not minted by `_beforeTokenTransfer` hook
        require(!_exists(tokenId), "ERC721: token already minted");

        unchecked {
            // Will not overflow unless all 2**256 token ids are minted to the same owner.
            // Given that tokens are minted one by one, it is impossible in practice that
            // this ever happens. Might change if we allow batch minting.
            // The ERC fails to describe this case.
            _balances[to] += 1;
        }

        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);

        _afterTokenTransfer(address(0), to, tokenId);
    }

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

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
        owner = ERC721.ownerOf(tokenId);

        // Clear approvals
        delete _tokenApprovals[tokenId];

        unchecked {
            // Cannot overflow, as that would require more tokens to be burned/transferred
            // out than the owner initially received through minting and transferring in.
            _balances[owner] -= 1;
        }
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);

        _afterTokenTransfer(owner, address(0), tokenId);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");

        // Clear approvals from the previous owner
        delete _tokenApprovals[tokenId];

        unchecked {
            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
            // `from`'s balance is the number of token held, which is at least one before the current
            // transfer.
            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
            // all 2**256 token ids to be minted, which in practice is impossible.
            _balances[from] -= 1;
            _balances[to] += 1;
        }
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits an {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC721: approve to caller");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Reverts if the `tokenId` has not been minted yet.
     */
    function _requireMinted(uint256 tokenId) internal view virtual {
        require(_exists(tokenId), "ERC721: invalid token ID");
    }

    /**
     * @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
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
}


// File: contracts/LightTrails_Flat.sol

pragma solidity ^0.8.4;

contract LightTrails is ERC721A, ERC721AQueryable, DefaultOperatorFilterer, Owned {
  uint256 public FIRST_MINT_PRICE = 0 ether;
  uint256 public EXTRA_MINT_PRICE = 0 ether;
  uint256 public FIRST_MINT_PRICE_PUBLIC = 0.02 ether;
  uint256 public EXTRA_MINT_PRICE_PUBLIC = 0.02 ether;
  uint256 constant MAX_SUPPLY_PLUS_ONE = 1001;
  uint256 constant MAX_PER_WALLET_PLUS_ONE = 6;
  uint256 RESERVED = 50;

  string tokenBaseUri = "ipfs://QmWowjx9HKytYNg9oPg96DtjJUvfx4ivg6p6bTXS1AeGhS/";

  bool public paused = true;
  bool public openToPublic = false;

  bytes32 public merkleRoot;

  mapping(address => uint256) private _freeMintedCount;
  mapping(address => uint256) private _totalMintedCount;
  mapping(address => bool) private _wLMinted;

  constructor(bytes32 _merkleRoot) ERC721A("LightTrails", "LTTrail") Owned(msg.sender) {
    merkleRoot = _merkleRoot;
  }

  function checkInWhiteList(bytes32[] calldata proof, uint256 quantity) view public returns(bool) {
    bytes32 leaf = keccak256(abi.encodePacked(msg.sender, quantity));
    bool verified = MerkleProof.verify(proof, merkleRoot, leaf);

    return verified;
  }

  // Rename mint function to optimize gas
  function mint_540(uint256 _quantity, bytes32[] calldata _proof) external payable {
    unchecked {
      require(!paused, "MINTING PAUSED");

      bool isWhiteListed = checkInWhiteList(_proof, _quantity);
      
      uint256 firstMintPrice;
      uint256 extraMintPrice;

      if(isWhiteListed && !openToPublic) {
        require(!_wLMinted[msg.sender], "ALREADY MINTED");
        firstMintPrice = FIRST_MINT_PRICE;
        extraMintPrice = EXTRA_MINT_PRICE;  
      } else {
        require(openToPublic, "MINTING NOT YET OPEN FOR PUBLIC");
        require(_totalMintedCount[msg.sender] + _quantity < MAX_PER_WALLET_PLUS_ONE, "MAX PER WALLET IS 5");
        firstMintPrice = FIRST_MINT_PRICE_PUBLIC;
        extraMintPrice = EXTRA_MINT_PRICE_PUBLIC;
      }
      
      uint256 _totalSupply = totalSupply();

      require(_totalSupply + _quantity + RESERVED < MAX_SUPPLY_PLUS_ONE, "MAX SUPPLY REACHED");

      uint256 payForCount = _quantity;
      uint256 payForFirstMint = 0;
      uint256 freeMintCount = _freeMintedCount[msg.sender];

      if (freeMintCount < 1) {
        if (_quantity > 1) {
          payForCount = _quantity - 1;
        } else {
          payForCount = 0;
        }
        payForFirstMint = 1;

        if(isWhiteListed && !openToPublic) {
            _freeMintedCount[msg.sender] = 0;
        } else {
            _freeMintedCount[msg.sender] = 1;
        }
      }
      if(isWhiteListed && !openToPublic) {
        _wLMinted[msg.sender] = true;
      } else {
        _totalMintedCount[msg.sender] += _quantity;
      }

      require(
        msg.value >= (payForCount * extraMintPrice + payForFirstMint * firstMintPrice),
        "INCORRECT ETH AMOUNT"
      );

      _mint(msg.sender, _quantity);
    }
  }

  // Set first mint price
  function setFirstMintPrice(uint256 _newPrice) public onlyOwner {
    FIRST_MINT_PRICE = _newPrice;
  }

  // Set extra mint price
  function setExtraMintPrice(uint256 _newPrice) public onlyOwner {
    EXTRA_MINT_PRICE = _newPrice;
  }

  // Set first mint price for public
  function setFirstMintPricePublic(uint256 _newPrice) public onlyOwner {
    FIRST_MINT_PRICE_PUBLIC = _newPrice;
  }

  // Set extra mint price for public
  function setExtraMintPricePublic(uint256 _newPrice) public onlyOwner {
    EXTRA_MINT_PRICE_PUBLIC = _newPrice;
  }

  function freeMintedCount(address owner) external view returns (uint256) {
    return _freeMintedCount[owner];
  }

  function totalMintedCount(address owner) external view returns (uint256) {
    return _totalMintedCount[owner];
  }

  function _startTokenId() internal pure override returns (uint256) {
    return 1;
  }

  function _baseURI() internal view override returns (string memory) {
    return tokenBaseUri;
  }

  function setBaseURI(string calldata _newBaseUri) external onlyOwner {
    tokenBaseUri = _newBaseUri;
  }

  function flipSale() external onlyOwner {
    paused = !paused;
  }

  function flipOpenToPublic() external onlyOwner {
    openToPublic = !openToPublic;
  }

  function collectReserves() external onlyOwner {
    require(RESERVED > 0, "RESERVES TAKEN");

    _mint(msg.sender, 50);
    RESERVED = 0;
  }

  function withdraw() external onlyOwner {
    require(
      payable(owner).send(address(this).balance),
      "UNSUCCESSFUL"
    );
  }

  function setApprovalForAll(address operator, bool approved) public override(ERC721A, IERC721A) onlyAllowedOperatorApproval(operator) {
    super.setApprovalForAll(operator, approved);
    }

    function approve(address operator, uint256 tokenId) public override(ERC721A, IERC721A) onlyAllowedOperatorApproval(operator) {
        super.approve(operator, tokenId);
    }

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

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

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"InvalidQueryRange","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","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":[],"name":"EXTRA_MINT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_MINT_PRICE_PUBLIC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FIRST_MINT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FIRST_MINT_PRICE_PUBLIC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"checkInWhiteList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"explicitOwnershipOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"explicitOwnershipsOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flipOpenToPublic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flipSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"freeMintedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"mint_540","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openToPublic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newBaseUri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"setExtraMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"setExtraMintPricePublic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"setFirstMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"setFirstMintPricePublic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"tokensOfOwnerIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"totalMintedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405260006009556000600a5566470de4df820000600b5566470de4df820000600c556032600d5560405180606001604052806036815260200162004e0d60369139600e90805190602001906200005a9291906200043d565b506001600f60006101000a81548160ff0219169083151502179055506000600f60016101000a81548160ff0219169083151502179055503480156200009e57600080fd5b5060405162004e4338038062004e438339818101604052810190620000c491906200052d565b33733cc6cdda760b79bafa08df41ecfa224f810dceb660016040518060400160405280600b81526020017f4c69676874547261696c730000000000000000000000000000000000000000008152506040518060400160405280600781526020017f4c54547261696c000000000000000000000000000000000000000000000000008152508160029080519060200190620001609291906200043d565b508060039080519060200190620001799291906200043d565b506200018a6200043460201b60201c565b600081905550505060006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115620003875780156200024d576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff16637d3e3dbe30846040518363ffffffff1660e01b815260040162000213929190620005a4565b600060405180830381600087803b1580156200022e57600080fd5b505af115801562000243573d6000803e3d6000fd5b5050505062000386565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161462000307576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663a0af290330846040518363ffffffff1660e01b8152600401620002cd929190620005a4565b600060405180830381600087803b158015620002e857600080fd5b505af1158015620002fd573d6000803e3d6000fd5b5050505062000385565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff16634420e486306040518263ffffffff1660e01b8152600401620003509190620005d1565b600060405180830381600087803b1580156200036b57600080fd5b505af115801562000380573d6000803e3d6000fd5b505050505b5b5b505080600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a350806010819055505062000652565b60006001905090565b8280546200044b906200061d565b90600052602060002090601f0160209004810192826200046f5760008555620004bb565b82601f106200048a57805160ff1916838001178555620004bb565b82800160010185558215620004bb579182015b82811115620004ba5782518255916020019190600101906200049d565b5b509050620004ca9190620004ce565b5090565b5b80821115620004e9576000816000905550600101620004cf565b5090565b600080fd5b6000819050919050565b6200050781620004f2565b81146200051357600080fd5b50565b6000815190506200052781620004fc565b92915050565b600060208284031215620005465762000545620004ed565b5b6000620005568482850162000516565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200058c826200055f565b9050919050565b6200059e816200057f565b82525050565b6000604082019050620005bb600083018562000593565b620005ca602083018462000593565b9392505050565b6000602082019050620005e8600083018462000593565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200063657607f821691505b6020821081036200064c576200064b620005ee565b5b50919050565b6147ab80620006626000396000f3fe60806040526004361061023b5760003560e01c80636352211e1161012e57806396b04c75116100ab578063b88d4fde1161006f578063b88d4fde14610850578063bfc28c0a14610879578063c23dc68f146108b6578063c87b56dd146108f3578063e985e9c5146109305761023b565b806396b04c7514610759578063981332351461078457806399a2557a146107c1578063a22cb465146107fe578063aaff97b4146108275761023b565b80638da5cb5b116100f25780638da5cb5b146106705780638ddbd1621461069b57806392ee4025146106d857806393b71a1a1461070357806395d89b411461072e5761023b565b80636352211e1461058657806367facf47146105c357806370a08231146105df5780637ba5e6211461061c5780638462151c146106335761023b565b80632052e89d116101bc5780634bda2fdc116101805780634bda2fdc146104a35780635401546b146104cc57806355f804b3146104f55780635bbb21771461051e5780635c975abb1461055b5761023b565b80632052e89d146103e657806323b872dd1461040f5780632eb4a7ab146104385780633ccfd60b1461046357806342842e0e1461047a5761023b565b8063081812fc11610203578063081812fc14610301578063095ea7b31461033e57806313af40351461036757806318160ddd146103905780631831ccf2146103bb5761023b565b806301ffc9a714610240578063029877b61461027d5780630370e1401461029457806303a7fef7146102ab57806306fdde03146102d6575b600080fd5b34801561024c57600080fd5b5061026760048036038101906102629190613547565b61096d565b604051610274919061358f565b60405180910390f35b34801561028957600080fd5b506102926109ff565b005b3480156102a057600080fd5b506102a9610ae9565b005b3480156102b757600080fd5b506102c0610ba5565b6040516102cd91906135c3565b60405180910390f35b3480156102e257600080fd5b506102eb610bab565b6040516102f89190613677565b60405180910390f35b34801561030d57600080fd5b50610328600480360381019061032391906136c5565b610c3d565b6040516103359190613733565b60405180910390f35b34801561034a57600080fd5b506103656004803603810190610360919061377a565b610cbc565b005b34801561037357600080fd5b5061038e600480360381019061038991906137ba565b610dc6565b005b34801561039c57600080fd5b506103a5610ef4565b6040516103b291906135c3565b60405180910390f35b3480156103c757600080fd5b506103d0610f0b565b6040516103dd919061358f565b60405180910390f35b3480156103f257600080fd5b5061040d600480360381019061040891906136c5565b610f1e565b005b34801561041b57600080fd5b50610436600480360381019061043191906137e7565b610fb8565b005b34801561044457600080fd5b5061044d611108565b60405161045a9190613853565b60405180910390f35b34801561046f57600080fd5b5061047861110e565b005b34801561048657600080fd5b506104a1600480360381019061049c91906137e7565b611236565b005b3480156104af57600080fd5b506104ca60048036038101906104c591906136c5565b611386565b005b3480156104d857600080fd5b506104f360048036038101906104ee91906136c5565b611420565b005b34801561050157600080fd5b5061051c600480360381019061051791906138d3565b6114ba565b005b34801561052a57600080fd5b5061054560048036038101906105409190613976565b611560565b6040516105529190613b26565b60405180910390f35b34801561056757600080fd5b50610570611623565b60405161057d919061358f565b60405180910390f35b34801561059257600080fd5b506105ad60048036038101906105a891906136c5565b611636565b6040516105ba9190613733565b60405180910390f35b6105dd60048036038101906105d89190613b9e565b611648565b005b3480156105eb57600080fd5b50610606600480360381019061060191906137ba565b611ae2565b60405161061391906135c3565b60405180910390f35b34801561062857600080fd5b50610631611b9a565b005b34801561063f57600080fd5b5061065a600480360381019061065591906137ba565b611c56565b6040516106679190613cbc565b60405180910390f35b34801561067c57600080fd5b50610685611d99565b6040516106929190613733565b60405180910390f35b3480156106a757600080fd5b506106c260048036038101906106bd9190613cde565b611dbf565b6040516106cf919061358f565b60405180910390f35b3480156106e457600080fd5b506106ed611e4b565b6040516106fa91906135c3565b60405180910390f35b34801561070f57600080fd5b50610718611e51565b60405161072591906135c3565b60405180910390f35b34801561073a57600080fd5b50610743611e57565b6040516107509190613677565b60405180910390f35b34801561076557600080fd5b5061076e611ee9565b60405161077b91906135c3565b60405180910390f35b34801561079057600080fd5b506107ab60048036038101906107a691906137ba565b611eef565b6040516107b891906135c3565b60405180910390f35b3480156107cd57600080fd5b506107e860048036038101906107e39190613d3e565b611f38565b6040516107f59190613cbc565b60405180910390f35b34801561080a57600080fd5b5061082560048036038101906108209190613dbd565b612144565b005b34801561083357600080fd5b5061084e600480360381019061084991906136c5565b61224e565b005b34801561085c57600080fd5b5061087760048036038101906108729190613f2d565b6122e8565b005b34801561088557600080fd5b506108a0600480360381019061089b91906137ba565b61243b565b6040516108ad91906135c3565b60405180910390f35b3480156108c257600080fd5b506108dd60048036038101906108d891906136c5565b612484565b6040516108ea9190614005565b60405180910390f35b3480156108ff57600080fd5b5061091a600480360381019061091591906136c5565b6124ee565b6040516109279190613677565b60405180910390f35b34801561093c57600080fd5b5061095760048036038101906109529190614020565b61258c565b604051610964919061358f565b60405180910390f35b60006301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806109c857506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109f85750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a86906140ac565b60405180910390fd5b6000600d5411610ad4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acb90614118565b60405180910390fd5b610adf336032612620565b6000600d81905550565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b70906140ac565b60405180910390fd5b600f60019054906101000a900460ff1615600f60016101000a81548160ff021916908315150217905550565b600b5481565b606060028054610bba90614167565b80601f0160208091040260200160405190810160405280929190818152602001828054610be690614167565b8015610c335780601f10610c0857610100808354040283529160200191610c33565b820191906000526020600020905b815481529060010190602001808311610c1657829003601f168201915b5050505050905090565b6000610c48826127db565b610c7e576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b8160006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115610db7576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401610d34929190614198565b602060405180830381865afa158015610d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7591906141d6565b610db657806040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401610dad9190613733565b60405180910390fd5b5b610dc1838361283a565b505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610e56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4d906140ac565b60405180910390fd5b80600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a350565b6000610efe61297e565b6001546000540303905090565b600f60019054906101000a900460ff1681565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610fae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fa5906140ac565b60405180910390fd5b8060098190555050565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156110f6573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361102a57611025848484612987565b611102565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401611073929190614198565b602060405180830381865afa158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b491906141d6565b6110f557336040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016110ec9190613733565b60405180910390fd5b5b611101848484612987565b5b50505050565b60105481565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461119e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611195906140ac565b60405180910390fd5b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050611234576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161122b9061424f565b60405180910390fd5b565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115611374573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036112a8576112a3848484612ca9565b611380565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b81526004016112f1929190614198565b602060405180830381865afa15801561130e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133291906141d6565b61137357336040517fede71dcc00000000000000000000000000000000000000000000000000000000815260040161136a9190613733565b60405180910390fd5b5b61137f848484612ca9565b5b50505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611416576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161140d906140ac565b60405180910390fd5b80600a8190555050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146114b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114a7906140ac565b60405180910390fd5b80600b8190555050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461154a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611541906140ac565b60405180910390fd5b8181600e919061155b9291906133e9565b505050565b6060600083839050905060008167ffffffffffffffff81111561158657611585613e02565b5b6040519080825280602002602001820160405280156115bf57816020015b6115ac61346f565b8152602001906001900390816115a45790505b50905060005b828114611617576115ee8686838181106115e2576115e161426f565b5b90506020020135612484565b8282815181106116015761160061426f565b5b60200260200101819052508060010190506115c5565b50809250505092915050565b600f60009054906101000a900460ff1681565b600061164182612cc9565b9050919050565b600f60009054906101000a900460ff1615611698576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161168f906142ea565b60405180910390fd5b60006116a5838386611dbf565b90506000808280156116c45750600f60019054906101000a900460ff16155b1561176557601360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611756576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161174d90614356565b60405180910390fd5b6009549150600a549050611843565b600f60019054906101000a900460ff166117b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117ab906143c2565b60405180910390fd5b600686601260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540110611838576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161182f9061442e565b60405180910390fd5b600b549150600c5490505b600061184d610ef4565b90506103e9600d548883010110611899576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118909061449a565b60405180910390fd5b6000879050600080601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060018110156119b95760018a11156119005760018a039250611905565b600092505b600191508680156119235750600f60019054906101000a900460ff16155b15611972576000601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506119b8565b6001601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5b8680156119d35750600f60019054906101000a900460ff16155b15611a35576001601360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611a83565b89601260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505b85820285840201341015611acc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ac390614506565b60405180910390fd5b611ad6338b612620565b50505050505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611b49576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054169050919050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c2a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c21906140ac565b60405180910390fd5b600f60009054906101000a900460ff1615600f60006101000a81548160ff021916908315150217905550565b60606000806000611c6685611ae2565b905060008167ffffffffffffffff811115611c8457611c83613e02565b5b604051908082528060200260200182016040528015611cb25781602001602082028036833780820191505090505b509050611cbd61346f565b6000611cc761297e565b90505b838614611d8b57611cda81612d95565b91508160400151611d8057600073ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff1614611d2557816000015194505b8773ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611d7f5780838780600101985081518110611d7257611d7161426f565b5b6020026020010181815250505b5b806001019050611cca565b508195505050505050919050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803383604051602001611dd592919061458f565b6040516020818303038152906040528051906020012090506000611e3d868680806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505060105484612dc0565b905080925050509392505050565b60095481565b600c5481565b606060038054611e6690614167565b80601f0160208091040260200160405190810160405280929190818152602001828054611e9290614167565b8015611edf5780601f10611eb457610100808354040283529160200191611edf565b820191906000526020600020905b815481529060010190602001808311611ec257829003601f168201915b5050505050905090565b600a5481565b6000601160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6060818310611f73576040517f32c1995a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080611f7e612dd7565b9050611f8861297e565b851015611f9a57611f9761297e565b94505b80841115611fa6578093505b6000611fb187611ae2565b905084861015611fd4576000868603905081811015611fce578091505b50611fd9565b600090505b60008167ffffffffffffffff811115611ff557611ff4613e02565b5b6040519080825280602002602001820160405280156120235781602001602082028036833780820191505090505b5090506000820361203a578094505050505061213d565b600061204588612484565b90506000816040015161205a57816000015190505b60008990505b8881141580156120705750848714155b1561212f5761207e81612d95565b9250826040015161212457600073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16146120c957826000015191505b8a73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361212357808488806001019950815181106121165761211561426f565b5b6020026020010181815250505b5b806001019050612060565b508583528296505050505050505b9392505050565b8160006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b111561223f576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b81526004016121bc929190614198565b602060405180830381865afa1580156121d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fd91906141d6565b61223e57806040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016122359190613733565b60405180910390fd5b5b6122498383612de0565b505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d5906140ac565b60405180910390fd5b80600c8190555050565b8360006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115612427573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361235b5761235685858585612eeb565b612434565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b81526004016123a4929190614198565b602060405180830381865afa1580156123c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e591906141d6565b61242657336040517fede71dcc00000000000000000000000000000000000000000000000000000000815260040161241d9190613733565b60405180910390fd5b5b61243385858585612eeb565b5b5050505050565b6000601260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b61248c61346f565b61249461346f565b61249c61297e565b8310806124b057506124ac612dd7565b8310155b156124be57809150506124e9565b6124c783612d95565b90508060400151156124dc57809150506124e9565b6124e583612f5e565b9150505b919050565b60606124f9826127db565b61252f576040517fa14c4b5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612539612f7e565b905060008151036125595760405180602001604052806000815250612584565b8061256384613010565b6040516020016125749291906145f7565b6040516020818303038152906040525b915050919050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60008054905060008203612660576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61266d6000848385613060565b600160406001901b178202600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055506126e4836126d56000866000613066565b6126de8561308e565b1761309e565b6004600083815260200190815260200160002081905550600080838301905073ffffffffffffffffffffffffffffffffffffffff85169150828260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600183015b81811461278557808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a460018101905061274a565b50600082036127c0576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060008190555050506127d660008483856130c9565b505050565b6000816127e661297e565b111580156127f5575060005482105b8015612833575060007c0100000000000000000000000000000000000000000000000000000000600460008581526020019081526020016000205416145b9050919050565b600061284582611636565b90508073ffffffffffffffffffffffffffffffffffffffff166128666130cf565b73ffffffffffffffffffffffffffffffffffffffff16146128c9576128928161288d6130cf565b61258c565b6128c8576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b826006600084815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b60006001905090565b600061299282612cc9565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146129f9576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080612a05846130d7565b91509150612a1b8187612a166130cf565b6130fe565b612a6757612a3086612a2b6130cf565b61258c565b612a66576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612acd576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ada8686866001613060565b8015612ae557600082555b600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081546001900391905081905550600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815460010191905081905550612bb385612b8f888887613066565b7c02000000000000000000000000000000000000000000000000000000001761309e565b600460008681526020019081526020016000208190555060007c0200000000000000000000000000000000000000000000000000000000841603612c395760006001850190506000600460008381526020019081526020016000205403612c37576000548114612c36578360046000838152602001908152602001600020819055505b5b505b838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4612ca186868660016130c9565b505050505050565b612cc4838383604051806020016040528060008152506122e8565b505050565b60008082905080612cd861297e565b11612d5e57600054811015612d5d5760006004600083815260200190815260200160002054905060007c0100000000000000000000000000000000000000000000000000000000821603612d5b575b60008103612d51576004600083600190039350838152602001908152602001600020549050612d27565b8092505050612d90565b505b5b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b612d9d61346f565b612db96004600084815260200190815260200160002054613142565b9050919050565b600082612dcd85846131f8565b1490509392505050565b60008054905090565b8060076000612ded6130cf565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16612e9a6130cf565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051612edf919061358f565b60405180910390a35050565b612ef6848484610fb8565b60008373ffffffffffffffffffffffffffffffffffffffff163b14612f5857612f218484848461324e565b612f57576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b50505050565b612f6661346f565b612f77612f7283612cc9565b613142565b9050919050565b6060600e8054612f8d90614167565b80601f0160208091040260200160405190810160405280929190818152602001828054612fb990614167565b80156130065780601f10612fdb57610100808354040283529160200191613006565b820191906000526020600020905b815481529060010190602001808311612fe957829003601f168201915b5050505050905090565b606060a060405101806040526020810391506000825281835b60011561304b57600184039350600a81066030018453600a8104905080613029575b50828103602084039350808452505050919050565b50505050565b60008060e883901c905060e861307d86868461339e565b62ffffff16901b9150509392505050565b60006001821460e11b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff83169250814260a01b178317905092915050565b50505050565b600033905090565b60008060006006600085815260200190815260200160002090508092508254915050915091565b600073ffffffffffffffffffffffffffffffffffffffff8316925073ffffffffffffffffffffffffffffffffffffffff821691508382148383141790509392505050565b61314a61346f565b81816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060a082901c816020019067ffffffffffffffff16908167ffffffffffffffff168152505060007c01000000000000000000000000000000000000000000000000000000008316141581604001901515908115158152505060e882901c816060019062ffffff16908162ffffff1681525050919050565b60008082905060005b84518110156132435761322e828683815181106132215761322061426f565b5b60200260200101516133a7565b9150808061323b9061464a565b915050613201565b508091505092915050565b60008373ffffffffffffffffffffffffffffffffffffffff1663150b7a026132746130cf565b8786866040518563ffffffff1660e01b815260040161329694939291906146e7565b6020604051808303816000875af19250505080156132d257506040513d601f19601f820116820180604052508101906132cf9190614748565b60015b61334b573d8060008114613302576040519150601f19603f3d011682016040523d82523d6000602084013e613307565b606091505b506000815103613343576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b60009392505050565b60008183106133bf576133ba82846133d2565b6133ca565b6133c983836133d2565b5b905092915050565b600082600052816020526040600020905092915050565b8280546133f590614167565b90600052602060002090601f016020900481019282613417576000855561345e565b82601f1061343057803560ff191683800117855561345e565b8280016001018555821561345e579182015b8281111561345d578235825591602001919060010190613442565b5b50905061346b91906134be565b5090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff168152602001600015158152602001600062ffffff1681525090565b5b808211156134d75760008160009055506001016134bf565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613524816134ef565b811461352f57600080fd5b50565b6000813590506135418161351b565b92915050565b60006020828403121561355d5761355c6134e5565b5b600061356b84828501613532565b91505092915050565b60008115159050919050565b61358981613574565b82525050565b60006020820190506135a46000830184613580565b92915050565b6000819050919050565b6135bd816135aa565b82525050565b60006020820190506135d860008301846135b4565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156136185780820151818401526020810190506135fd565b83811115613627576000848401525b50505050565b6000601f19601f8301169050919050565b6000613649826135de565b61365381856135e9565b93506136638185602086016135fa565b61366c8161362d565b840191505092915050565b60006020820190508181036000830152613691818461363e565b905092915050565b6136a2816135aa565b81146136ad57600080fd5b50565b6000813590506136bf81613699565b92915050565b6000602082840312156136db576136da6134e5565b5b60006136e9848285016136b0565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061371d826136f2565b9050919050565b61372d81613712565b82525050565b60006020820190506137486000830184613724565b92915050565b61375781613712565b811461376257600080fd5b50565b6000813590506137748161374e565b92915050565b60008060408385031215613791576137906134e5565b5b600061379f85828601613765565b92505060206137b0858286016136b0565b9150509250929050565b6000602082840312156137d0576137cf6134e5565b5b60006137de84828501613765565b91505092915050565b600080600060608486031215613800576137ff6134e5565b5b600061380e86828701613765565b935050602061381f86828701613765565b9250506040613830868287016136b0565b9150509250925092565b6000819050919050565b61384d8161383a565b82525050565b60006020820190506138686000830184613844565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126138935761389261386e565b5b8235905067ffffffffffffffff8111156138b0576138af613873565b5b6020830191508360018202830111156138cc576138cb613878565b5b9250929050565b600080602083850312156138ea576138e96134e5565b5b600083013567ffffffffffffffff811115613908576139076134ea565b5b6139148582860161387d565b92509250509250929050565b60008083601f8401126139365761393561386e565b5b8235905067ffffffffffffffff81111561395357613952613873565b5b60208301915083602082028301111561396f5761396e613878565b5b9250929050565b6000806020838503121561398d5761398c6134e5565b5b600083013567ffffffffffffffff8111156139ab576139aa6134ea565b5b6139b785828601613920565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6139f881613712565b82525050565b600067ffffffffffffffff82169050919050565b613a1b816139fe565b82525050565b613a2a81613574565b82525050565b600062ffffff82169050919050565b613a4881613a30565b82525050565b608082016000820151613a6460008501826139ef565b506020820151613a776020850182613a12565b506040820151613a8a6040850182613a21565b506060820151613a9d6060850182613a3f565b50505050565b6000613aaf8383613a4e565b60808301905092915050565b6000602082019050919050565b6000613ad3826139c3565b613add81856139ce565b9350613ae8836139df565b8060005b83811015613b19578151613b008882613aa3565b9750613b0b83613abb565b925050600181019050613aec565b5085935050505092915050565b60006020820190508181036000830152613b408184613ac8565b905092915050565b60008083601f840112613b5e57613b5d61386e565b5b8235905067ffffffffffffffff811115613b7b57613b7a613873565b5b602083019150836020820283011115613b9757613b96613878565b5b9250929050565b600080600060408486031215613bb757613bb66134e5565b5b6000613bc5868287016136b0565b935050602084013567ffffffffffffffff811115613be657613be56134ea565b5b613bf286828701613b48565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b613c33816135aa565b82525050565b6000613c458383613c2a565b60208301905092915050565b6000602082019050919050565b6000613c6982613bfe565b613c738185613c09565b9350613c7e83613c1a565b8060005b83811015613caf578151613c968882613c39565b9750613ca183613c51565b925050600181019050613c82565b5085935050505092915050565b60006020820190508181036000830152613cd68184613c5e565b905092915050565b600080600060408486031215613cf757613cf66134e5565b5b600084013567ffffffffffffffff811115613d1557613d146134ea565b5b613d2186828701613b48565b93509350506020613d34868287016136b0565b9150509250925092565b600080600060608486031215613d5757613d566134e5565b5b6000613d6586828701613765565b9350506020613d76868287016136b0565b9250506040613d87868287016136b0565b9150509250925092565b613d9a81613574565b8114613da557600080fd5b50565b600081359050613db781613d91565b92915050565b60008060408385031215613dd457613dd36134e5565b5b6000613de285828601613765565b9250506020613df385828601613da8565b9150509250929050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613e3a8261362d565b810181811067ffffffffffffffff82111715613e5957613e58613e02565b5b80604052505050565b6000613e6c6134db565b9050613e788282613e31565b919050565b600067ffffffffffffffff821115613e9857613e97613e02565b5b613ea18261362d565b9050602081019050919050565b82818337600083830152505050565b6000613ed0613ecb84613e7d565b613e62565b905082815260208101848484011115613eec57613eeb613dfd565b5b613ef7848285613eae565b509392505050565b600082601f830112613f1457613f1361386e565b5b8135613f24848260208601613ebd565b91505092915050565b60008060008060808587031215613f4757613f466134e5565b5b6000613f5587828801613765565b9450506020613f6687828801613765565b9350506040613f77878288016136b0565b925050606085013567ffffffffffffffff811115613f9857613f976134ea565b5b613fa487828801613eff565b91505092959194509250565b608082016000820151613fc660008501826139ef565b506020820151613fd96020850182613a12565b506040820151613fec6040850182613a21565b506060820151613fff6060850182613a3f565b50505050565b600060808201905061401a6000830184613fb0565b92915050565b60008060408385031215614037576140366134e5565b5b600061404585828601613765565b925050602061405685828601613765565b9150509250929050565b7f554e415554484f52495a45440000000000000000000000000000000000000000600082015250565b6000614096600c836135e9565b91506140a182614060565b602082019050919050565b600060208201905081810360008301526140c581614089565b9050919050565b7f52455345525645532054414b454e000000000000000000000000000000000000600082015250565b6000614102600e836135e9565b915061410d826140cc565b602082019050919050565b60006020820190508181036000830152614131816140f5565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061417f57607f821691505b60208210810361419257614191614138565b5b50919050565b60006040820190506141ad6000830185613724565b6141ba6020830184613724565b9392505050565b6000815190506141d081613d91565b92915050565b6000602082840312156141ec576141eb6134e5565b5b60006141fa848285016141c1565b91505092915050565b7f554e5355434345535346554c0000000000000000000000000000000000000000600082015250565b6000614239600c836135e9565b915061424482614203565b602082019050919050565b600060208201905081810360008301526142688161422c565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4d494e54494e4720504155534544000000000000000000000000000000000000600082015250565b60006142d4600e836135e9565b91506142df8261429e565b602082019050919050565b60006020820190508181036000830152614303816142c7565b9050919050565b7f414c5245414459204d494e544544000000000000000000000000000000000000600082015250565b6000614340600e836135e9565b915061434b8261430a565b602082019050919050565b6000602082019050818103600083015261436f81614333565b9050919050565b7f4d494e54494e47204e4f5420594554204f50454e20464f52205055424c494300600082015250565b60006143ac601f836135e9565b91506143b782614376565b602082019050919050565b600060208201905081810360008301526143db8161439f565b9050919050565b7f4d4158205045522057414c4c4554204953203500000000000000000000000000600082015250565b60006144186013836135e9565b9150614423826143e2565b602082019050919050565b600060208201905081810360008301526144478161440b565b9050919050565b7f4d415820535550504c5920524541434845440000000000000000000000000000600082015250565b60006144846012836135e9565b915061448f8261444e565b602082019050919050565b600060208201905081810360008301526144b381614477565b9050919050565b7f494e434f52524543542045544820414d4f554e54000000000000000000000000600082015250565b60006144f06014836135e9565b91506144fb826144ba565b602082019050919050565b6000602082019050818103600083015261451f816144e3565b9050919050565b60008160601b9050919050565b600061453e82614526565b9050919050565b600061455082614533565b9050919050565b61456861456382613712565b614545565b82525050565b6000819050919050565b614589614584826135aa565b61456e565b82525050565b600061459b8285614557565b6014820191506145ab8284614578565b6020820191508190509392505050565b600081905092915050565b60006145d1826135de565b6145db81856145bb565b93506145eb8185602086016135fa565b80840191505092915050565b600061460382856145c6565b915061460f82846145c6565b91508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614655826135aa565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036146875761468661461b565b5b600182019050919050565b600081519050919050565b600082825260208201905092915050565b60006146b982614692565b6146c3818561469d565b93506146d38185602086016135fa565b6146dc8161362d565b840191505092915050565b60006080820190506146fc6000830187613724565b6147096020830186613724565b61471660408301856135b4565b818103606083015261472881846146ae565b905095945050505050565b6000815190506147428161351b565b92915050565b60006020828403121561475e5761475d6134e5565b5b600061476c84828501614733565b9150509291505056fea26469706673582212205fa18252be9c00bebf740c7643df3691b882bb18c8e3afd3a4c0b5c7eb1965a664736f6c634300080d0033697066733a2f2f516d576f776a7839484b7974594e67396f5067393644746a4a5576667834697667367036625458533141654768532f74fe99a3f69aab96ccd399609157ada321b7375c0884efffa696c05ad1358aff

Deployed Bytecode

0x60806040526004361061023b5760003560e01c80636352211e1161012e57806396b04c75116100ab578063b88d4fde1161006f578063b88d4fde14610850578063bfc28c0a14610879578063c23dc68f146108b6578063c87b56dd146108f3578063e985e9c5146109305761023b565b806396b04c7514610759578063981332351461078457806399a2557a146107c1578063a22cb465146107fe578063aaff97b4146108275761023b565b80638da5cb5b116100f25780638da5cb5b146106705780638ddbd1621461069b57806392ee4025146106d857806393b71a1a1461070357806395d89b411461072e5761023b565b80636352211e1461058657806367facf47146105c357806370a08231146105df5780637ba5e6211461061c5780638462151c146106335761023b565b80632052e89d116101bc5780634bda2fdc116101805780634bda2fdc146104a35780635401546b146104cc57806355f804b3146104f55780635bbb21771461051e5780635c975abb1461055b5761023b565b80632052e89d146103e657806323b872dd1461040f5780632eb4a7ab146104385780633ccfd60b1461046357806342842e0e1461047a5761023b565b8063081812fc11610203578063081812fc14610301578063095ea7b31461033e57806313af40351461036757806318160ddd146103905780631831ccf2146103bb5761023b565b806301ffc9a714610240578063029877b61461027d5780630370e1401461029457806303a7fef7146102ab57806306fdde03146102d6575b600080fd5b34801561024c57600080fd5b5061026760048036038101906102629190613547565b61096d565b604051610274919061358f565b60405180910390f35b34801561028957600080fd5b506102926109ff565b005b3480156102a057600080fd5b506102a9610ae9565b005b3480156102b757600080fd5b506102c0610ba5565b6040516102cd91906135c3565b60405180910390f35b3480156102e257600080fd5b506102eb610bab565b6040516102f89190613677565b60405180910390f35b34801561030d57600080fd5b50610328600480360381019061032391906136c5565b610c3d565b6040516103359190613733565b60405180910390f35b34801561034a57600080fd5b506103656004803603810190610360919061377a565b610cbc565b005b34801561037357600080fd5b5061038e600480360381019061038991906137ba565b610dc6565b005b34801561039c57600080fd5b506103a5610ef4565b6040516103b291906135c3565b60405180910390f35b3480156103c757600080fd5b506103d0610f0b565b6040516103dd919061358f565b60405180910390f35b3480156103f257600080fd5b5061040d600480360381019061040891906136c5565b610f1e565b005b34801561041b57600080fd5b50610436600480360381019061043191906137e7565b610fb8565b005b34801561044457600080fd5b5061044d611108565b60405161045a9190613853565b60405180910390f35b34801561046f57600080fd5b5061047861110e565b005b34801561048657600080fd5b506104a1600480360381019061049c91906137e7565b611236565b005b3480156104af57600080fd5b506104ca60048036038101906104c591906136c5565b611386565b005b3480156104d857600080fd5b506104f360048036038101906104ee91906136c5565b611420565b005b34801561050157600080fd5b5061051c600480360381019061051791906138d3565b6114ba565b005b34801561052a57600080fd5b5061054560048036038101906105409190613976565b611560565b6040516105529190613b26565b60405180910390f35b34801561056757600080fd5b50610570611623565b60405161057d919061358f565b60405180910390f35b34801561059257600080fd5b506105ad60048036038101906105a891906136c5565b611636565b6040516105ba9190613733565b60405180910390f35b6105dd60048036038101906105d89190613b9e565b611648565b005b3480156105eb57600080fd5b50610606600480360381019061060191906137ba565b611ae2565b60405161061391906135c3565b60405180910390f35b34801561062857600080fd5b50610631611b9a565b005b34801561063f57600080fd5b5061065a600480360381019061065591906137ba565b611c56565b6040516106679190613cbc565b60405180910390f35b34801561067c57600080fd5b50610685611d99565b6040516106929190613733565b60405180910390f35b3480156106a757600080fd5b506106c260048036038101906106bd9190613cde565b611dbf565b6040516106cf919061358f565b60405180910390f35b3480156106e457600080fd5b506106ed611e4b565b6040516106fa91906135c3565b60405180910390f35b34801561070f57600080fd5b50610718611e51565b60405161072591906135c3565b60405180910390f35b34801561073a57600080fd5b50610743611e57565b6040516107509190613677565b60405180910390f35b34801561076557600080fd5b5061076e611ee9565b60405161077b91906135c3565b60405180910390f35b34801561079057600080fd5b506107ab60048036038101906107a691906137ba565b611eef565b6040516107b891906135c3565b60405180910390f35b3480156107cd57600080fd5b506107e860048036038101906107e39190613d3e565b611f38565b6040516107f59190613cbc565b60405180910390f35b34801561080a57600080fd5b5061082560048036038101906108209190613dbd565b612144565b005b34801561083357600080fd5b5061084e600480360381019061084991906136c5565b61224e565b005b34801561085c57600080fd5b5061087760048036038101906108729190613f2d565b6122e8565b005b34801561088557600080fd5b506108a0600480360381019061089b91906137ba565b61243b565b6040516108ad91906135c3565b60405180910390f35b3480156108c257600080fd5b506108dd60048036038101906108d891906136c5565b612484565b6040516108ea9190614005565b60405180910390f35b3480156108ff57600080fd5b5061091a600480360381019061091591906136c5565b6124ee565b6040516109279190613677565b60405180910390f35b34801561093c57600080fd5b5061095760048036038101906109529190614020565b61258c565b604051610964919061358f565b60405180910390f35b60006301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806109c857506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109f85750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a86906140ac565b60405180910390fd5b6000600d5411610ad4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acb90614118565b60405180910390fd5b610adf336032612620565b6000600d81905550565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b70906140ac565b60405180910390fd5b600f60019054906101000a900460ff1615600f60016101000a81548160ff021916908315150217905550565b600b5481565b606060028054610bba90614167565b80601f0160208091040260200160405190810160405280929190818152602001828054610be690614167565b8015610c335780601f10610c0857610100808354040283529160200191610c33565b820191906000526020600020905b815481529060010190602001808311610c1657829003601f168201915b5050505050905090565b6000610c48826127db565b610c7e576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b8160006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115610db7576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401610d34929190614198565b602060405180830381865afa158015610d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7591906141d6565b610db657806040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401610dad9190613733565b60405180910390fd5b5b610dc1838361283a565b505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610e56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4d906140ac565b60405180910390fd5b80600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a350565b6000610efe61297e565b6001546000540303905090565b600f60019054906101000a900460ff1681565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610fae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fa5906140ac565b60405180910390fd5b8060098190555050565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b11156110f6573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361102a57611025848484612987565b611102565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b8152600401611073929190614198565b602060405180830381865afa158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b491906141d6565b6110f557336040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016110ec9190613733565b60405180910390fd5b5b611101848484612987565b5b50505050565b60105481565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461119e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611195906140ac565b60405180910390fd5b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050611234576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161122b9061424f565b60405180910390fd5b565b8260006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115611374573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036112a8576112a3848484612ca9565b611380565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b81526004016112f1929190614198565b602060405180830381865afa15801561130e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133291906141d6565b61137357336040517fede71dcc00000000000000000000000000000000000000000000000000000000815260040161136a9190613733565b60405180910390fd5b5b61137f848484612ca9565b5b50505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611416576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161140d906140ac565b60405180910390fd5b80600a8190555050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146114b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114a7906140ac565b60405180910390fd5b80600b8190555050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461154a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611541906140ac565b60405180910390fd5b8181600e919061155b9291906133e9565b505050565b6060600083839050905060008167ffffffffffffffff81111561158657611585613e02565b5b6040519080825280602002602001820160405280156115bf57816020015b6115ac61346f565b8152602001906001900390816115a45790505b50905060005b828114611617576115ee8686838181106115e2576115e161426f565b5b90506020020135612484565b8282815181106116015761160061426f565b5b60200260200101819052508060010190506115c5565b50809250505092915050565b600f60009054906101000a900460ff1681565b600061164182612cc9565b9050919050565b600f60009054906101000a900460ff1615611698576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161168f906142ea565b60405180910390fd5b60006116a5838386611dbf565b90506000808280156116c45750600f60019054906101000a900460ff16155b1561176557601360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611756576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161174d90614356565b60405180910390fd5b6009549150600a549050611843565b600f60019054906101000a900460ff166117b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117ab906143c2565b60405180910390fd5b600686601260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540110611838576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161182f9061442e565b60405180910390fd5b600b549150600c5490505b600061184d610ef4565b90506103e9600d548883010110611899576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118909061449a565b60405180910390fd5b6000879050600080601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060018110156119b95760018a11156119005760018a039250611905565b600092505b600191508680156119235750600f60019054906101000a900460ff16155b15611972576000601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506119b8565b6001601160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5b8680156119d35750600f60019054906101000a900460ff16155b15611a35576001601360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611a83565b89601260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505b85820285840201341015611acc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ac390614506565b60405180910390fd5b611ad6338b612620565b50505050505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611b49576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054169050919050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c2a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c21906140ac565b60405180910390fd5b600f60009054906101000a900460ff1615600f60006101000a81548160ff021916908315150217905550565b60606000806000611c6685611ae2565b905060008167ffffffffffffffff811115611c8457611c83613e02565b5b604051908082528060200260200182016040528015611cb25781602001602082028036833780820191505090505b509050611cbd61346f565b6000611cc761297e565b90505b838614611d8b57611cda81612d95565b91508160400151611d8057600073ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff1614611d2557816000015194505b8773ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611d7f5780838780600101985081518110611d7257611d7161426f565b5b6020026020010181815250505b5b806001019050611cca565b508195505050505050919050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803383604051602001611dd592919061458f565b6040516020818303038152906040528051906020012090506000611e3d868680806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505060105484612dc0565b905080925050509392505050565b60095481565b600c5481565b606060038054611e6690614167565b80601f0160208091040260200160405190810160405280929190818152602001828054611e9290614167565b8015611edf5780601f10611eb457610100808354040283529160200191611edf565b820191906000526020600020905b815481529060010190602001808311611ec257829003601f168201915b5050505050905090565b600a5481565b6000601160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6060818310611f73576040517f32c1995a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080611f7e612dd7565b9050611f8861297e565b851015611f9a57611f9761297e565b94505b80841115611fa6578093505b6000611fb187611ae2565b905084861015611fd4576000868603905081811015611fce578091505b50611fd9565b600090505b60008167ffffffffffffffff811115611ff557611ff4613e02565b5b6040519080825280602002602001820160405280156120235781602001602082028036833780820191505090505b5090506000820361203a578094505050505061213d565b600061204588612484565b90506000816040015161205a57816000015190505b60008990505b8881141580156120705750848714155b1561212f5761207e81612d95565b9250826040015161212457600073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16146120c957826000015191505b8a73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361212357808488806001019950815181106121165761211561426f565b5b6020026020010181815250505b5b806001019050612060565b508583528296505050505050505b9392505050565b8160006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b111561223f576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b81526004016121bc929190614198565b602060405180830381865afa1580156121d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fd91906141d6565b61223e57806040517fede71dcc0000000000000000000000000000000000000000000000000000000081526004016122359190613733565b60405180910390fd5b5b6122498383612de0565b505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d5906140ac565b60405180910390fd5b80600c8190555050565b8360006daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115612427573373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361235b5761235685858585612eeb565b612434565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430336040518363ffffffff1660e01b81526004016123a4929190614198565b602060405180830381865afa1580156123c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e591906141d6565b61242657336040517fede71dcc00000000000000000000000000000000000000000000000000000000815260040161241d9190613733565b60405180910390fd5b5b61243385858585612eeb565b5b5050505050565b6000601260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b61248c61346f565b61249461346f565b61249c61297e565b8310806124b057506124ac612dd7565b8310155b156124be57809150506124e9565b6124c783612d95565b90508060400151156124dc57809150506124e9565b6124e583612f5e565b9150505b919050565b60606124f9826127db565b61252f576040517fa14c4b5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612539612f7e565b905060008151036125595760405180602001604052806000815250612584565b8061256384613010565b6040516020016125749291906145f7565b6040516020818303038152906040525b915050919050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60008054905060008203612660576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61266d6000848385613060565b600160406001901b178202600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055506126e4836126d56000866000613066565b6126de8561308e565b1761309e565b6004600083815260200190815260200160002081905550600080838301905073ffffffffffffffffffffffffffffffffffffffff85169150828260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600183015b81811461278557808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a460018101905061274a565b50600082036127c0576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060008190555050506127d660008483856130c9565b505050565b6000816127e661297e565b111580156127f5575060005482105b8015612833575060007c0100000000000000000000000000000000000000000000000000000000600460008581526020019081526020016000205416145b9050919050565b600061284582611636565b90508073ffffffffffffffffffffffffffffffffffffffff166128666130cf565b73ffffffffffffffffffffffffffffffffffffffff16146128c9576128928161288d6130cf565b61258c565b6128c8576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b826006600084815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b60006001905090565b600061299282612cc9565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146129f9576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080612a05846130d7565b91509150612a1b8187612a166130cf565b6130fe565b612a6757612a3086612a2b6130cf565b61258c565b612a66576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612acd576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ada8686866001613060565b8015612ae557600082555b600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081546001900391905081905550600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815460010191905081905550612bb385612b8f888887613066565b7c02000000000000000000000000000000000000000000000000000000001761309e565b600460008681526020019081526020016000208190555060007c0200000000000000000000000000000000000000000000000000000000841603612c395760006001850190506000600460008381526020019081526020016000205403612c37576000548114612c36578360046000838152602001908152602001600020819055505b5b505b838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4612ca186868660016130c9565b505050505050565b612cc4838383604051806020016040528060008152506122e8565b505050565b60008082905080612cd861297e565b11612d5e57600054811015612d5d5760006004600083815260200190815260200160002054905060007c0100000000000000000000000000000000000000000000000000000000821603612d5b575b60008103612d51576004600083600190039350838152602001908152602001600020549050612d27565b8092505050612d90565b505b5b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b612d9d61346f565b612db96004600084815260200190815260200160002054613142565b9050919050565b600082612dcd85846131f8565b1490509392505050565b60008054905090565b8060076000612ded6130cf565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16612e9a6130cf565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051612edf919061358f565b60405180910390a35050565b612ef6848484610fb8565b60008373ffffffffffffffffffffffffffffffffffffffff163b14612f5857612f218484848461324e565b612f57576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b50505050565b612f6661346f565b612f77612f7283612cc9565b613142565b9050919050565b6060600e8054612f8d90614167565b80601f0160208091040260200160405190810160405280929190818152602001828054612fb990614167565b80156130065780601f10612fdb57610100808354040283529160200191613006565b820191906000526020600020905b815481529060010190602001808311612fe957829003601f168201915b5050505050905090565b606060a060405101806040526020810391506000825281835b60011561304b57600184039350600a81066030018453600a8104905080613029575b50828103602084039350808452505050919050565b50505050565b60008060e883901c905060e861307d86868461339e565b62ffffff16901b9150509392505050565b60006001821460e11b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff83169250814260a01b178317905092915050565b50505050565b600033905090565b60008060006006600085815260200190815260200160002090508092508254915050915091565b600073ffffffffffffffffffffffffffffffffffffffff8316925073ffffffffffffffffffffffffffffffffffffffff821691508382148383141790509392505050565b61314a61346f565b81816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060a082901c816020019067ffffffffffffffff16908167ffffffffffffffff168152505060007c01000000000000000000000000000000000000000000000000000000008316141581604001901515908115158152505060e882901c816060019062ffffff16908162ffffff1681525050919050565b60008082905060005b84518110156132435761322e828683815181106132215761322061426f565b5b60200260200101516133a7565b9150808061323b9061464a565b915050613201565b508091505092915050565b60008373ffffffffffffffffffffffffffffffffffffffff1663150b7a026132746130cf565b8786866040518563ffffffff1660e01b815260040161329694939291906146e7565b6020604051808303816000875af19250505080156132d257506040513d601f19601f820116820180604052508101906132cf9190614748565b60015b61334b573d8060008114613302576040519150601f19603f3d011682016040523d82523d6000602084013e613307565b606091505b506000815103613343576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b60009392505050565b60008183106133bf576133ba82846133d2565b6133ca565b6133c983836133d2565b5b905092915050565b600082600052816020526040600020905092915050565b8280546133f590614167565b90600052602060002090601f016020900481019282613417576000855561345e565b82601f1061343057803560ff191683800117855561345e565b8280016001018555821561345e579182015b8281111561345d578235825591602001919060010190613442565b5b50905061346b91906134be565b5090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff168152602001600015158152602001600062ffffff1681525090565b5b808211156134d75760008160009055506001016134bf565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613524816134ef565b811461352f57600080fd5b50565b6000813590506135418161351b565b92915050565b60006020828403121561355d5761355c6134e5565b5b600061356b84828501613532565b91505092915050565b60008115159050919050565b61358981613574565b82525050565b60006020820190506135a46000830184613580565b92915050565b6000819050919050565b6135bd816135aa565b82525050565b60006020820190506135d860008301846135b4565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156136185780820151818401526020810190506135fd565b83811115613627576000848401525b50505050565b6000601f19601f8301169050919050565b6000613649826135de565b61365381856135e9565b93506136638185602086016135fa565b61366c8161362d565b840191505092915050565b60006020820190508181036000830152613691818461363e565b905092915050565b6136a2816135aa565b81146136ad57600080fd5b50565b6000813590506136bf81613699565b92915050565b6000602082840312156136db576136da6134e5565b5b60006136e9848285016136b0565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061371d826136f2565b9050919050565b61372d81613712565b82525050565b60006020820190506137486000830184613724565b92915050565b61375781613712565b811461376257600080fd5b50565b6000813590506137748161374e565b92915050565b60008060408385031215613791576137906134e5565b5b600061379f85828601613765565b92505060206137b0858286016136b0565b9150509250929050565b6000602082840312156137d0576137cf6134e5565b5b60006137de84828501613765565b91505092915050565b600080600060608486031215613800576137ff6134e5565b5b600061380e86828701613765565b935050602061381f86828701613765565b9250506040613830868287016136b0565b9150509250925092565b6000819050919050565b61384d8161383a565b82525050565b60006020820190506138686000830184613844565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126138935761389261386e565b5b8235905067ffffffffffffffff8111156138b0576138af613873565b5b6020830191508360018202830111156138cc576138cb613878565b5b9250929050565b600080602083850312156138ea576138e96134e5565b5b600083013567ffffffffffffffff811115613908576139076134ea565b5b6139148582860161387d565b92509250509250929050565b60008083601f8401126139365761393561386e565b5b8235905067ffffffffffffffff81111561395357613952613873565b5b60208301915083602082028301111561396f5761396e613878565b5b9250929050565b6000806020838503121561398d5761398c6134e5565b5b600083013567ffffffffffffffff8111156139ab576139aa6134ea565b5b6139b785828601613920565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6139f881613712565b82525050565b600067ffffffffffffffff82169050919050565b613a1b816139fe565b82525050565b613a2a81613574565b82525050565b600062ffffff82169050919050565b613a4881613a30565b82525050565b608082016000820151613a6460008501826139ef565b506020820151613a776020850182613a12565b506040820151613a8a6040850182613a21565b506060820151613a9d6060850182613a3f565b50505050565b6000613aaf8383613a4e565b60808301905092915050565b6000602082019050919050565b6000613ad3826139c3565b613add81856139ce565b9350613ae8836139df565b8060005b83811015613b19578151613b008882613aa3565b9750613b0b83613abb565b925050600181019050613aec565b5085935050505092915050565b60006020820190508181036000830152613b408184613ac8565b905092915050565b60008083601f840112613b5e57613b5d61386e565b5b8235905067ffffffffffffffff811115613b7b57613b7a613873565b5b602083019150836020820283011115613b9757613b96613878565b5b9250929050565b600080600060408486031215613bb757613bb66134e5565b5b6000613bc5868287016136b0565b935050602084013567ffffffffffffffff811115613be657613be56134ea565b5b613bf286828701613b48565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b613c33816135aa565b82525050565b6000613c458383613c2a565b60208301905092915050565b6000602082019050919050565b6000613c6982613bfe565b613c738185613c09565b9350613c7e83613c1a565b8060005b83811015613caf578151613c968882613c39565b9750613ca183613c51565b925050600181019050613c82565b5085935050505092915050565b60006020820190508181036000830152613cd68184613c5e565b905092915050565b600080600060408486031215613cf757613cf66134e5565b5b600084013567ffffffffffffffff811115613d1557613d146134ea565b5b613d2186828701613b48565b93509350506020613d34868287016136b0565b9150509250925092565b600080600060608486031215613d5757613d566134e5565b5b6000613d6586828701613765565b9350506020613d76868287016136b0565b9250506040613d87868287016136b0565b9150509250925092565b613d9a81613574565b8114613da557600080fd5b50565b600081359050613db781613d91565b92915050565b60008060408385031215613dd457613dd36134e5565b5b6000613de285828601613765565b9250506020613df385828601613da8565b9150509250929050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613e3a8261362d565b810181811067ffffffffffffffff82111715613e5957613e58613e02565b5b80604052505050565b6000613e6c6134db565b9050613e788282613e31565b919050565b600067ffffffffffffffff821115613e9857613e97613e02565b5b613ea18261362d565b9050602081019050919050565b82818337600083830152505050565b6000613ed0613ecb84613e7d565b613e62565b905082815260208101848484011115613eec57613eeb613dfd565b5b613ef7848285613eae565b509392505050565b600082601f830112613f1457613f1361386e565b5b8135613f24848260208601613ebd565b91505092915050565b60008060008060808587031215613f4757613f466134e5565b5b6000613f5587828801613765565b9450506020613f6687828801613765565b9350506040613f77878288016136b0565b925050606085013567ffffffffffffffff811115613f9857613f976134ea565b5b613fa487828801613eff565b91505092959194509250565b608082016000820151613fc660008501826139ef565b506020820151613fd96020850182613a12565b506040820151613fec6040850182613a21565b506060820151613fff6060850182613a3f565b50505050565b600060808201905061401a6000830184613fb0565b92915050565b60008060408385031215614037576140366134e5565b5b600061404585828601613765565b925050602061405685828601613765565b9150509250929050565b7f554e415554484f52495a45440000000000000000000000000000000000000000600082015250565b6000614096600c836135e9565b91506140a182614060565b602082019050919050565b600060208201905081810360008301526140c581614089565b9050919050565b7f52455345525645532054414b454e000000000000000000000000000000000000600082015250565b6000614102600e836135e9565b915061410d826140cc565b602082019050919050565b60006020820190508181036000830152614131816140f5565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061417f57607f821691505b60208210810361419257614191614138565b5b50919050565b60006040820190506141ad6000830185613724565b6141ba6020830184613724565b9392505050565b6000815190506141d081613d91565b92915050565b6000602082840312156141ec576141eb6134e5565b5b60006141fa848285016141c1565b91505092915050565b7f554e5355434345535346554c0000000000000000000000000000000000000000600082015250565b6000614239600c836135e9565b915061424482614203565b602082019050919050565b600060208201905081810360008301526142688161422c565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4d494e54494e4720504155534544000000000000000000000000000000000000600082015250565b60006142d4600e836135e9565b91506142df8261429e565b602082019050919050565b60006020820190508181036000830152614303816142c7565b9050919050565b7f414c5245414459204d494e544544000000000000000000000000000000000000600082015250565b6000614340600e836135e9565b915061434b8261430a565b602082019050919050565b6000602082019050818103600083015261436f81614333565b9050919050565b7f4d494e54494e47204e4f5420594554204f50454e20464f52205055424c494300600082015250565b60006143ac601f836135e9565b91506143b782614376565b602082019050919050565b600060208201905081810360008301526143db8161439f565b9050919050565b7f4d4158205045522057414c4c4554204953203500000000000000000000000000600082015250565b60006144186013836135e9565b9150614423826143e2565b602082019050919050565b600060208201905081810360008301526144478161440b565b9050919050565b7f4d415820535550504c5920524541434845440000000000000000000000000000600082015250565b60006144846012836135e9565b915061448f8261444e565b602082019050919050565b600060208201905081810360008301526144b381614477565b9050919050565b7f494e434f52524543542045544820414d4f554e54000000000000000000000000600082015250565b60006144f06014836135e9565b91506144fb826144ba565b602082019050919050565b6000602082019050818103600083015261451f816144e3565b9050919050565b60008160601b9050919050565b600061453e82614526565b9050919050565b600061455082614533565b9050919050565b61456861456382613712565b614545565b82525050565b6000819050919050565b614589614584826135aa565b61456e565b82525050565b600061459b8285614557565b6014820191506145ab8284614578565b6020820191508190509392505050565b600081905092915050565b60006145d1826135de565b6145db81856145bb565b93506145eb8185602086016135fa565b80840191505092915050565b600061460382856145c6565b915061460f82846145c6565b91508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614655826135aa565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036146875761468661461b565b5b600182019050919050565b600081519050919050565b600082825260208201905092915050565b60006146b982614692565b6146c3818561469d565b93506146d38185602086016135fa565b6146dc8161362d565b840191505092915050565b60006080820190506146fc6000830187613724565b6147096020830186613724565b61471660408301856135b4565b818103606083015261472881846146ae565b905095945050505050565b6000815190506147428161351b565b92915050565b60006020828403121561475e5761475d6134e5565b5b600061476c84828501614733565b9150509291505056fea26469706673582212205fa18252be9c00bebf740c7643df3691b882bb18c8e3afd3a4c0b5c7eb1965a664736f6c634300080d0033

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

74fe99a3f69aab96ccd399609157ada321b7375c0884efffa696c05ad1358aff

-----Decoded View---------------
Arg [0] : _merkleRoot (bytes32): 0x74fe99a3f69aab96ccd399609157ada321b7375c0884efffa696c05ad1358aff

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 74fe99a3f69aab96ccd399609157ada321b7375c0884efffa696c05ad1358aff


Deployed Bytecode Sourcemap

114915:5653:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33339:639;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;119248:147;;;;;;;;;;;;;:::i;:::-;;119154:88;;;;;;;;;;;;;:::i;:::-;;115094:51;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;34241:100;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;40724:218;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;119746:176;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;76524:148;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;29992:323;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115446:32;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;117956:104;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;119930:182;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;115485:25;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;119401:140;;;;;;;;;;;;;:::i;:::-;;120120:190;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;118093:104;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;118241:117;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;118967:107;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;70364:528;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115416:25;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;35634:152;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;116121:1802;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;31176:233;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;119080:68;;;;;;;;;;;;;:::i;:::-;;74240:900;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;75888:20;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115809:263;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115002:41;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115150:51;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;34417:104;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115048:41;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;118525:115;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;71280:2513;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;119547:191;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;118402:117;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;120318:247;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;118646:117;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;69777:428;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;34627:318;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;41673:164;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;33339:639;33424:4;33763:10;33748:25;;:11;:25;;;;:102;;;;33840:10;33825:25;;:11;:25;;;;33748:102;:179;;;;33917:10;33902:25;;:11;:25;;;;33748:179;33728:199;;33339:639;;;:::o;119248:147::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;119320:1:::1;119309:8;;:12;119301:39;;;;;;;;;;;;:::i;:::-;;;;;;;;;119349:21;119355:10;119367:2;119349:5;:21::i;:::-;119388:1;119377:8;:12;;;;119248:147::o:0;119154:88::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;119224:12:::1;;;;;;;;;;;119223:13;119208:12;;:28;;;;;;;;;;;;;;;;;;119154:88::o:0;115094:51::-;;;;:::o;34241:100::-;34295:13;34328:5;34321:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34241:100;:::o;40724:218::-;40800:7;40825:16;40833:7;40825;:16::i;:::-;40820:64;;40850:34;;;;;;;;;;;;;;40820:64;40904:15;:24;40920:7;40904:24;;;;;;;;;;;:30;;;;;;;;;;;;40897:37;;40724:218;;;:::o;119746:176::-;119861:8;4634:1;2692:42;4586:45;;;:49;4582:225;;;2692:42;4657;;;4708:4;4715:8;4657:67;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4652:144;;4771:8;4752:28;;;;;;;;;;;:::i;:::-;;;;;;;;4652:144;4582:225;119882:32:::1;119896:8;119906:7;119882:13;:32::i;:::-;119746:176:::0;;;:::o;76524:148::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;76604:8:::1;76596:5;;:16;;;;;;;;;;;;;;;;;;76655:8;76630:34;;76643:10;76630:34;;;;;;;;;;;;76524:148:::0;:::o;29992:323::-;30053:7;30281:15;:13;:15::i;:::-;30266:12;;30250:13;;:28;:46;30243:53;;29992:323;:::o;115446:32::-;;;;;;;;;;;;;:::o;117956:104::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;118045:9:::1;118026:16;:28;;;;117956:104:::0;:::o;119930:182::-;120050:4;3888:1;2692:42;3840:45;;;:49;3836:539;;;4129:10;4121:18;;:4;:18;;;4117:85;;120067:37:::1;120086:4;120092:2;120096:7;120067:18;:37::i;:::-;4180:7:::0;;4117:85;2692:42;4221;;;4272:4;4279:10;4221:69;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4216:148;;4337:10;4318:30;;;;;;;;;;;:::i;:::-;;;;;;;;4216:148;3836:539;120067:37:::1;120086:4;120092:2;120096:7;120067:18;:37::i;:::-;119930:182:::0;;;;;:::o;115485:25::-;;;;:::o;119401:140::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;119471:5:::1;;;;;;;;;;;119463:19;;:42;119483:21;119463:42;;;;;;;;;;;;;;;;;;;;;;;119447:88;;;;;;;;;;;;:::i;:::-;;;;;;;;;119401:140::o:0;120120:190::-;120244:4;3888:1;2692:42;3840:45;;;:49;3836:539;;;4129:10;4121:18;;:4;:18;;;4117:85;;120261:41:::1;120284:4;120290:2;120294:7;120261:22;:41::i;:::-;4180:7:::0;;4117:85;2692:42;4221;;;4272:4;4279:10;4221:69;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4216:148;;4337:10;4318:30;;;;;;;;;;;:::i;:::-;;;;;;;;4216:148;3836:539;120261:41:::1;120284:4;120290:2;120294:7;120261:22;:41::i;:::-;120120:190:::0;;;;;:::o;118093:104::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;118182:9:::1;118163:16;:28;;;;118093:104:::0;:::o;118241:117::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;118343:9:::1;118317:23;:35;;;;118241:117:::0;:::o;118967:107::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;119057:11:::1;;119042:12;:26;;;;;;;:::i;:::-;;118967:107:::0;;:::o;70364:528::-;70508:23;70574:22;70599:8;;:15;;70574:40;;70629:34;70687:14;70666:36;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;70629:73;;70722:9;70717:125;70738:14;70733:1;:19;70717:125;;70794:32;70814:8;;70823:1;70814:11;;;;;;;:::i;:::-;;;;;;;;70794:19;:32::i;:::-;70778:10;70789:1;70778:13;;;;;;;;:::i;:::-;;;;;;;:48;;;;70754:3;;;;;70717:125;;;;70863:10;70856:17;;;;70364:528;;;;:::o;115416:25::-;;;;;;;;;;;;;:::o;35634:152::-;35706:7;35749:27;35768:7;35749:18;:27::i;:::-;35726:52;;35634:152;;;:::o;116121:1802::-;116237:6;;;;;;;;;;;116236:7;116228:34;;;;;;;;;;;;:::i;:::-;;;;;;;;;116273:18;116294:35;116311:6;;116319:9;116294:16;:35::i;:::-;116273:56;;116346:22;116377;116413:13;:30;;;;;116431:12;;;;;;;;;;;116430:13;116413:30;116410:490;;;116465:9;:21;116475:10;116465:21;;;;;;;;;;;;;;;;;;;;;;;;;116464:22;116456:49;;;;;;;;;;;;:::i;:::-;;;;;;;;;116533:16;;116516:33;;116577:16;;116560:33;;116410:490;;;116630:12;;;;;;;;;;;116622:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;115297:1;116729:9;116697:17;:29;116715:10;116697:29;;;;;;;;;;;;;;;;:41;:67;116689:99;;;;;;;;;;;;:::i;:::-;;;;;;;;;116816:23;;116799:40;;116867:23;;116850:40;;116410:490;116916:20;116939:13;:11;:13::i;:::-;116916:36;;115245:4;116998:8;;116986:9;116971:12;:24;:35;:57;116963:88;;;;;;;;;;;;:::i;:::-;;;;;;;;;117062:19;117084:9;117062:31;;117102:23;117138:21;117162:16;:28;117179:10;117162:28;;;;;;;;;;;;;;;;117138:52;;117221:1;117205:13;:17;117201:361;;;117251:1;117239:9;:13;117235:117;;;117293:1;117281:9;:13;117267:27;;117235:117;;;117339:1;117325:15;;117235:117;117380:1;117362:19;;117397:13;:30;;;;;117415:12;;;;;;;;;;;117414:13;117397:30;117394:159;;;117475:1;117444:16;:28;117461:10;117444:28;;;;;;;;;;;;;;;:32;;;;117394:159;;;117540:1;117509:16;:28;117526:10;117509:28;;;;;;;;;;;;;;;:32;;;;117394:159;117201:361;117573:13;:30;;;;;117591:12;;;;;;;;;;;117590:13;117573:30;117570:153;;;117640:4;117616:9;:21;117626:10;117616:21;;;;;;;;;;;;;;;;:28;;;;;;;;;;;;;;;;;;117570:153;;;117704:9;117671:17;:29;117689:10;117671:29;;;;;;;;;;;;;;;;:42;;;;;;;;;;;117570:153;117814:14;117796:15;:32;117779:14;117765:11;:28;:63;117751:9;:78;;117733:138;;;;;;;;;;;;:::i;:::-;;;;;;;;;117882:28;117888:10;117900:9;117882:5;:28::i;:::-;116209:1709;;;;;;;116121:1802;;;:::o;31176:233::-;31248:7;31289:1;31272:19;;:5;:19;;;31268:60;;31300:28;;;;;;;;;;;;;;31268:60;25335:13;31346:18;:25;31365:5;31346:25;;;;;;;;;;;;;;;;:55;31339:62;;31176:233;;;:::o;119080:68::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;119136:6:::1;;;;;;;;;;;119135:7;119126:6;;:16;;;;;;;;;;;;;;;;;;119080:68::o:0;74240:900::-;74318:16;74372:19;74406:25;74446:22;74471:16;74481:5;74471:9;:16::i;:::-;74446:41;;74502:25;74544:14;74530:29;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74502:57;;74574:31;;:::i;:::-;74625:9;74637:15;:13;:15::i;:::-;74625:27;;74620:472;74669:14;74654:11;:29;74620:472;;74721:15;74734:1;74721:12;:15::i;:::-;74709:27;;74759:9;:16;;;74800:8;74755:73;74876:1;74850:28;;:9;:14;;;:28;;;74846:111;;74923:9;:14;;;74903:34;;74846:111;75000:5;74979:26;;:17;:26;;;74975:102;;75056:1;75030:8;75039:13;;;;;;75030:23;;;;;;;;:::i;:::-;;;;;;;:27;;;;;74975:102;74620:472;74685:3;;;;;74620:472;;;;75113:8;75106:15;;;;;;;74240:900;;;:::o;75888:20::-;;;;;;;;;;;;;:::o;115809:263::-;115899:4;115912:12;115954:10;115966:8;115937:38;;;;;;;;;:::i;:::-;;;;;;;;;;;;;115927:49;;;;;;115912:64;;115983:13;115999:43;116018:5;;115999:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;116025:10;;116037:4;115999:18;:43::i;:::-;115983:59;;116058:8;116051:15;;;;115809:263;;;;;:::o;115002:41::-;;;;:::o;115150:51::-;;;;:::o;34417:104::-;34473:13;34506:7;34499:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34417:104;:::o;115048:41::-;;;;:::o;118525:115::-;118588:7;118611:16;:23;118628:5;118611:23;;;;;;;;;;;;;;;;118604:30;;118525:115;;;:::o;71280:2513::-;71423:16;71490:4;71481:5;:13;71477:45;;71503:19;;;;;;;;;;;;;;71477:45;71537:19;71571:17;71591:14;:12;:14::i;:::-;71571:34;;71691:15;:13;:15::i;:::-;71683:5;:23;71679:87;;;71735:15;:13;:15::i;:::-;71727:23;;71679:87;71842:9;71835:4;:16;71831:73;;;71879:9;71872:16;;71831:73;71918:25;71946:16;71956:5;71946:9;:16::i;:::-;71918:44;;72140:4;72132:5;:12;72128:278;;;72165:19;72194:5;72187:4;:12;72165:34;;72236:17;72222:11;:31;72218:111;;;72298:11;72278:31;;72218:111;72146:198;72128:278;;;72389:1;72369:21;;72128:278;72420:25;72462:17;72448:32;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;72420:60;;72520:1;72499:17;:22;72495:78;;72549:8;72542:15;;;;;;;;72495:78;72717:31;72751:26;72771:5;72751:19;:26::i;:::-;72717:60;;72792:25;73037:9;:16;;;73032:92;;73094:9;:14;;;73074:34;;73032:92;73143:9;73155:5;73143:17;;73138:478;73167:4;73162:1;:9;;:45;;;;;73190:17;73175:11;:32;;73162:45;73138:478;;;73245:15;73258:1;73245:12;:15::i;:::-;73233:27;;73283:9;:16;;;73324:8;73279:73;73400:1;73374:28;;:9;:14;;;:28;;;73370:111;;73447:9;:14;;;73427:34;;73370:111;73524:5;73503:26;;:17;:26;;;73499:102;;73580:1;73554:8;73563:13;;;;;;73554:23;;;;;;;;:::i;:::-;;;;;;;:27;;;;;73499:102;73138:478;73209:3;;;;;73138:478;;;;73718:11;73708:8;73701:29;73766:8;73759:15;;;;;;;;71280:2513;;;;;;:::o;119547:191::-;119670:8;4634:1;2692:42;4586:45;;;:49;4582:225;;;2692:42;4657;;;4708:4;4715:8;4657:67;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4652:144;;4771:8;4752:28;;;;;;;;;;;:::i;:::-;;;;;;;;4652:144;4582:225;119687:43:::1;119711:8;119721;119687:23;:43::i;:::-;119547:191:::0;;;:::o;118402:117::-;75979:5;;;;;;;;;;;75965:19;;:10;:19;;;75957:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;118504:9:::1;118478:23;:35;;;;118402:117:::0;:::o;120318:247::-;120488:4;3888:1;2692:42;3840:45;;;:49;3836:539;;;4129:10;4121:18;;:4;:18;;;4117:85;;120510:47:::1;120533:4;120539:2;120543:7;120552:4;120510:22;:47::i;:::-;4180:7:::0;;4117:85;2692:42;4221;;;4272:4;4279:10;4221:69;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4216:148;;4337:10;4318:30;;;;;;;;;;;:::i;:::-;;;;;;;;4216:148;3836:539;120510:47:::1;120533:4;120539:2;120543:7;120552:4;120510:22;:47::i;:::-;120318:247:::0;;;;;;:::o;118646:117::-;118710:7;118733:17;:24;118751:5;118733:24;;;;;;;;;;;;;;;;118726:31;;118646:117;;;:::o;69777:428::-;69861:21;;:::i;:::-;69895:31;;:::i;:::-;69951:15;:13;:15::i;:::-;69941:7;:25;:54;;;;69981:14;:12;:14::i;:::-;69970:7;:25;;69941:54;69937:103;;;70019:9;70012:16;;;;;69937:103;70062:21;70075:7;70062:12;:21::i;:::-;70050:33;;70098:9;:16;;;70094:65;;;70138:9;70131:16;;;;;70094:65;70176:21;70189:7;70176:12;:21::i;:::-;70169:28;;;69777:428;;;;:::o;34627:318::-;34700:13;34731:16;34739:7;34731;:16::i;:::-;34726:59;;34756:29;;;;;;;;;;;;;;34726:59;34798:21;34822:10;:8;:10::i;:::-;34798:34;;34875:1;34856:7;34850:21;:26;:87;;;;;;;;;;;;;;;;;34903:7;34912:18;34922:7;34912:9;:18::i;:::-;34886:45;;;;;;;;;:::i;:::-;;;;;;;;;;;;;34850:87;34843:94;;;34627:318;;;:::o;41673:164::-;41770:4;41794:18;:25;41813:5;41794:25;;;;;;;;;;;;;;;:35;41820:8;41794:35;;;;;;;;;;;;;;;;;;;;;;;;;41787:42;;41673:164;;;;:::o;51720:2720::-;51793:20;51816:13;;51793:36;;51856:1;51844:8;:13;51840:44;;51866:18;;;;;;;;;;;;;;51840:44;51897:61;51927:1;51931:2;51935:12;51949:8;51897:21;:61::i;:::-;52441:1;25473:2;52411:1;:26;;52410:32;52398:8;:45;52372:18;:22;52391:2;52372:22;;;;;;;;;;;;;;;;:71;;;;;;;;;;;52720:139;52757:2;52811:33;52834:1;52838:2;52842:1;52811:14;:33::i;:::-;52778:30;52799:8;52778:20;:30::i;:::-;:66;52720:18;:139::i;:::-;52686:17;:31;52704:12;52686:31;;;;;;;;;;;:173;;;;52876:16;52907:11;52936:8;52921:12;:23;52907:37;;53457:16;53453:2;53449:25;53437:37;;53829:12;53789:8;53748:1;53686:25;53627:1;53566;53539:335;53954:1;53940:12;53936:20;53894:346;53995:3;53986:7;53983:16;53894:346;;54213:7;54203:8;54200:1;54173:25;54170:1;54167;54162:59;54048:1;54039:7;54035:15;54024:26;;53894:346;;;53898:77;54285:1;54273:8;:13;54269:45;;54295:19;;;;;;;;;;;;;;54269:45;54347:3;54331:13;:19;;;;52146:2216;;54372:60;54401:1;54405:2;54409:12;54423:8;54372:20;:60::i;:::-;51782:2658;51720:2720;;:::o;42095:282::-;42160:4;42216:7;42197:15;:13;:15::i;:::-;:26;;:66;;;;;42250:13;;42240:7;:23;42197:66;:153;;;;;42349:1;26111:8;42301:17;:26;42319:7;42301:26;;;;;;;;;;;;:44;:49;42197:153;42177:173;;42095:282;;;:::o;40165:400::-;40246:13;40262:16;40270:7;40262;:16::i;:::-;40246:32;;40318:5;40295:28;;:19;:17;:19::i;:::-;:28;;;40291:175;;40343:44;40360:5;40367:19;:17;:19::i;:::-;40343:16;:44::i;:::-;40338:128;;40415:35;;;;;;;;;;;;;;40338:128;40291:175;40511:2;40478:15;:24;40494:7;40478:24;;;;;;;;;;;:30;;;:35;;;;;;;;;;;;;;;;;;40549:7;40545:2;40529:28;;40538:5;40529:28;;;;;;;;;;;;40235:330;40165:400;;:::o;118769:87::-;118826:7;118849:1;118842:8;;118769:87;:::o;44363:2817::-;44497:27;44527;44546:7;44527:18;:27::i;:::-;44497:57;;44612:4;44571:45;;44587:19;44571:45;;;44567:86;;44625:28;;;;;;;;;;;;;;44567:86;44667:27;44696:23;44723:35;44750:7;44723:26;:35::i;:::-;44666:92;;;;44858:68;44883:15;44900:4;44906:19;:17;:19::i;:::-;44858:24;:68::i;:::-;44853:180;;44946:43;44963:4;44969:19;:17;:19::i;:::-;44946:16;:43::i;:::-;44941:92;;44998:35;;;;;;;;;;;;;;44941:92;44853:180;45064:1;45050:16;;:2;:16;;;45046:52;;45075:23;;;;;;;;;;;;;;45046:52;45111:43;45133:4;45139:2;45143:7;45152:1;45111:21;:43::i;:::-;45247:15;45244:160;;;45387:1;45366:19;45359:30;45244:160;45784:18;:24;45803:4;45784:24;;;;;;;;;;;;;;;;45782:26;;;;;;;;;;;;45853:18;:22;45872:2;45853:22;;;;;;;;;;;;;;;;45851:24;;;;;;;;;;;46175:146;46212:2;46261:45;46276:4;46282:2;46286:19;46261:14;:45::i;:::-;26391:8;46233:73;46175:18;:146::i;:::-;46146:17;:26;46164:7;46146:26;;;;;;;;;;;:175;;;;46492:1;26391:8;46441:19;:47;:52;46437:627;;46514:19;46546:1;46536:7;:11;46514:33;;46703:1;46669:17;:30;46687:11;46669:30;;;;;;;;;;;;:35;46665:384;;46807:13;;46792:11;:28;46788:242;;46987:19;46954:17;:30;46972:11;46954:30;;;;;;;;;;;:52;;;;46788:242;46665:384;46495:569;46437:627;47111:7;47107:2;47092:27;;47101:4;47092:27;;;;;;;;;;;;47130:42;47151:4;47157:2;47161:7;47170:1;47130:20;:42::i;:::-;44486:2694;;;44363:2817;;;:::o;47276:185::-;47414:39;47431:4;47437:2;47441:7;47414:39;;;;;;;;;;;;:16;:39::i;:::-;47276:185;;;:::o;36789:1275::-;36856:7;36876:12;36891:7;36876:22;;36959:4;36940:15;:13;:15::i;:::-;:23;36936:1061;;36993:13;;36986:4;:20;36982:1015;;;37031:14;37048:17;:23;37066:4;37048:23;;;;;;;;;;;;37031:40;;37165:1;26111:8;37137:6;:24;:29;37133:845;;37802:113;37819:1;37809:6;:11;37802:113;;37862:17;:25;37880:6;;;;;;;37862:25;;;;;;;;;;;;37853:34;;37802:113;;;37948:6;37941:13;;;;;;37133:845;37008:989;36982:1015;36936:1061;38025:31;;;;;;;;;;;;;;36789:1275;;;;:::o;36237:161::-;36305:21;;:::i;:::-;36346:44;36365:17;:24;36383:5;36365:24;;;;;;;;;;;;36346:18;:44::i;:::-;36339:51;;36237:161;;;:::o;6548:190::-;6673:4;6726;6697:25;6710:5;6717:4;6697:12;:25::i;:::-;:33;6690:40;;6548:190;;;;;:::o;29679:103::-;29734:7;29761:13;;29754:20;;29679:103;:::o;41282:234::-;41429:8;41377:18;:39;41396:19;:17;:19::i;:::-;41377:39;;;;;;;;;;;;;;;:49;41417:8;41377:49;;;;;;;;;;;;;;;;:60;;;;;;;;;;;;;;;;;;41489:8;41453:55;;41468:19;:17;:19::i;:::-;41453:55;;;41499:8;41453:55;;;;;;:::i;:::-;;;;;;;;41282:234;;:::o;48059:399::-;48226:31;48239:4;48245:2;48249:7;48226:12;:31::i;:::-;48290:1;48272:2;:14;;;:19;48268:183;;48311:56;48342:4;48348:2;48352:7;48361:5;48311:30;:56::i;:::-;48306:145;;48395:40;;;;;;;;;;;;;;48306:145;48268:183;48059:399;;;;:::o;35975:166::-;36045:21;;:::i;:::-;36086:47;36105:27;36124:7;36105:18;:27::i;:::-;36086:18;:47::i;:::-;36079:54;;35975:166;;;:::o;118862:99::-;118914:13;118943:12;118936:19;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;118862:99;:::o;64340:1745::-;64405:17;64839:4;64832;64826:11;64822:22;64931:1;64925:4;64918:15;65006:4;65003:1;64999:12;64992:19;;65088:1;65083:3;65076:14;65192:3;65431:5;65413:428;65439:1;65413:428;;;65479:1;65474:3;65470:11;65463:18;;65650:2;65644:4;65640:13;65636:2;65632:22;65627:3;65619:36;65744:2;65738:4;65734:13;65726:21;;65811:4;65413:428;65801:25;65413:428;65417:21;65880:3;65875;65871:13;65995:4;65990:3;65986:14;65979:21;;66060:6;66055:3;66048:19;64444:1634;;;64340:1745;;;:::o;49120:159::-;;;;;:::o;63442:311::-;63577:7;63597:16;26515:3;63623:19;:41;;63597:68;;26515:3;63691:31;63702:4;63708:2;63712:9;63691:10;:31::i;:::-;63683:40;;:62;;63676:69;;;63442:311;;;;;:::o;39164:324::-;39234:14;39467:1;39457:8;39454:15;39428:24;39424:46;39414:56;;39164:324;;;:::o;38612:450::-;38692:14;38860:16;38853:5;38849:28;38840:37;;39037:5;39023:11;38998:23;38994:41;38991:52;38984:5;38981:63;38971:73;;38612:450;;;;:::o;49944:158::-;;;;;:::o;64133:105::-;64193:7;64220:10;64213:17;;64133:105;:::o;43258:485::-;43360:27;43389:23;43430:38;43471:15;:24;43487:7;43471:24;;;;;;;;;;;43430:65;;43648:18;43625:41;;43705:19;43699:26;43680:45;;43610:126;43258:485;;;:::o;42486:659::-;42635:11;42800:16;42793:5;42789:28;42780:37;;42960:16;42949:9;42945:32;42932:45;;43110:15;43099:9;43096:30;43088:5;43077:9;43074:20;43071:56;43061:66;;42486:659;;;;;:::o;38163:366::-;38229:31;;:::i;:::-;38306:6;38273:9;:14;;:41;;;;;;;;;;;25994:3;38359:6;:33;;38325:9;:24;;:68;;;;;;;;;;;38451:1;26111:8;38423:6;:24;:29;;38404:9;:16;;:48;;;;;;;;;;;26515:3;38492:6;:28;;38463:9;:19;;:58;;;;;;;;;;;38163:366;;;:::o;7415:296::-;7498:7;7518:20;7541:4;7518:27;;7561:9;7556:118;7580:5;:12;7576:1;:16;7556:118;;;7629:33;7639:12;7653:5;7659:1;7653:8;;;;;;;;:::i;:::-;;;;;;;;7629:9;:33::i;:::-;7614:48;;7594:3;;;;;:::i;:::-;;;;7556:118;;;;7691:12;7684:19;;;7415:296;;;;:::o;50542:716::-;50705:4;50751:2;50726:45;;;50772:19;:17;:19::i;:::-;50793:4;50799:7;50808:5;50726:88;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;50722:529;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51026:1;51009:6;:13;:18;51005:235;;51055:40;;;;;;;;;;;;;;51005:235;51198:6;51192:13;51183:6;51179:2;51175:15;51168:38;50722:529;50895:54;;;50885:64;;;:6;:64;;;;50878:71;;;50542:716;;;;;;:::o;63143:147::-;63280:6;63143:147;;;;;:::o;14455:149::-;14518:7;14549:1;14545;:5;:51;;14576:20;14591:1;14594;14576:14;:20::i;:::-;14545:51;;;14553:20;14568:1;14571;14553:14;:20::i;:::-;14545:51;14538:58;;14455:149;;;;:::o;14612:268::-;14680:13;14787:1;14781:4;14774:15;14816:1;14810:4;14803:15;14857:4;14851;14841:21;14832:30;;14612:268;;;;:::o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::o;7:75:1:-;40:6;73:2;67:9;57:19;;7:75;:::o;88:117::-;197:1;194;187:12;211:117;320:1;317;310:12;334:149;370:7;410:66;403:5;399:78;388:89;;334:149;;;:::o;489:120::-;561:23;578:5;561:23;:::i;:::-;554:5;551:34;541:62;;599:1;596;589:12;541:62;489:120;:::o;615:137::-;660:5;698:6;685:20;676:29;;714:32;740:5;714:32;:::i;:::-;615:137;;;;:::o;758:327::-;816:6;865:2;853:9;844:7;840:23;836:32;833:119;;;871:79;;:::i;:::-;833:119;991:1;1016:52;1060:7;1051:6;1040:9;1036:22;1016:52;:::i;:::-;1006:62;;962:116;758:327;;;;:::o;1091:90::-;1125:7;1168:5;1161:13;1154:21;1143:32;;1091:90;;;:::o;1187:109::-;1268:21;1283:5;1268:21;:::i;:::-;1263:3;1256:34;1187:109;;:::o;1302:210::-;1389:4;1427:2;1416:9;1412:18;1404:26;;1440:65;1502:1;1491:9;1487:17;1478:6;1440:65;:::i;:::-;1302:210;;;;:::o;1518:77::-;1555:7;1584:5;1573:16;;1518:77;;;:::o;1601:118::-;1688:24;1706:5;1688:24;:::i;:::-;1683:3;1676:37;1601:118;;:::o;1725:222::-;1818:4;1856:2;1845:9;1841:18;1833:26;;1869:71;1937:1;1926:9;1922:17;1913:6;1869:71;:::i;:::-;1725:222;;;;:::o;1953:99::-;2005:6;2039:5;2033:12;2023:22;;1953:99;;;:::o;2058:169::-;2142:11;2176:6;2171:3;2164:19;2216:4;2211:3;2207:14;2192:29;;2058:169;;;;:::o;2233:307::-;2301:1;2311:113;2325:6;2322:1;2319:13;2311:113;;;2410:1;2405:3;2401:11;2395:18;2391:1;2386:3;2382:11;2375:39;2347:2;2344:1;2340:10;2335:15;;2311:113;;;2442:6;2439:1;2436:13;2433:101;;;2522:1;2513:6;2508:3;2504:16;2497:27;2433:101;2282:258;2233:307;;;:::o;2546:102::-;2587:6;2638:2;2634:7;2629:2;2622:5;2618:14;2614:28;2604:38;;2546:102;;;:::o;2654:364::-;2742:3;2770:39;2803:5;2770:39;:::i;:::-;2825:71;2889:6;2884:3;2825:71;:::i;:::-;2818:78;;2905:52;2950:6;2945:3;2938:4;2931:5;2927:16;2905:52;:::i;:::-;2982:29;3004:6;2982:29;:::i;:::-;2977:3;2973:39;2966:46;;2746:272;2654:364;;;;:::o;3024:313::-;3137:4;3175:2;3164:9;3160:18;3152:26;;3224:9;3218:4;3214:20;3210:1;3199:9;3195:17;3188:47;3252:78;3325:4;3316:6;3252:78;:::i;:::-;3244:86;;3024:313;;;;:::o;3343:122::-;3416:24;3434:5;3416:24;:::i;:::-;3409:5;3406:35;3396:63;;3455:1;3452;3445:12;3396:63;3343:122;:::o;3471:139::-;3517:5;3555:6;3542:20;3533:29;;3571:33;3598:5;3571:33;:::i;:::-;3471:139;;;;:::o;3616:329::-;3675:6;3724:2;3712:9;3703:7;3699:23;3695:32;3692:119;;;3730:79;;:::i;:::-;3692:119;3850:1;3875:53;3920:7;3911:6;3900:9;3896:22;3875:53;:::i;:::-;3865:63;;3821:117;3616:329;;;;:::o;3951:126::-;3988:7;4028:42;4021:5;4017:54;4006:65;;3951:126;;;:::o;4083:96::-;4120:7;4149:24;4167:5;4149:24;:::i;:::-;4138:35;;4083:96;;;:::o;4185:118::-;4272:24;4290:5;4272:24;:::i;:::-;4267:3;4260:37;4185:118;;:::o;4309:222::-;4402:4;4440:2;4429:9;4425:18;4417:26;;4453:71;4521:1;4510:9;4506:17;4497:6;4453:71;:::i;:::-;4309:222;;;;:::o;4537:122::-;4610:24;4628:5;4610:24;:::i;:::-;4603:5;4600:35;4590:63;;4649:1;4646;4639:12;4590:63;4537:122;:::o;4665:139::-;4711:5;4749:6;4736:20;4727:29;;4765:33;4792:5;4765:33;:::i;:::-;4665:139;;;;:::o;4810:474::-;4878:6;4886;4935:2;4923:9;4914:7;4910:23;4906:32;4903:119;;;4941:79;;:::i;:::-;4903:119;5061:1;5086:53;5131:7;5122:6;5111:9;5107:22;5086:53;:::i;:::-;5076:63;;5032:117;5188:2;5214:53;5259:7;5250:6;5239:9;5235:22;5214:53;:::i;:::-;5204:63;;5159:118;4810:474;;;;;:::o;5290:329::-;5349:6;5398:2;5386:9;5377:7;5373:23;5369:32;5366:119;;;5404:79;;:::i;:::-;5366:119;5524:1;5549:53;5594:7;5585:6;5574:9;5570:22;5549:53;:::i;:::-;5539:63;;5495:117;5290:329;;;;:::o;5625:619::-;5702:6;5710;5718;5767:2;5755:9;5746:7;5742:23;5738:32;5735:119;;;5773:79;;:::i;:::-;5735:119;5893:1;5918:53;5963:7;5954:6;5943:9;5939:22;5918:53;:::i;:::-;5908:63;;5864:117;6020:2;6046:53;6091:7;6082:6;6071:9;6067:22;6046:53;:::i;:::-;6036:63;;5991:118;6148:2;6174:53;6219:7;6210:6;6199:9;6195:22;6174:53;:::i;:::-;6164:63;;6119:118;5625:619;;;;;:::o;6250:77::-;6287:7;6316:5;6305:16;;6250:77;;;:::o;6333:118::-;6420:24;6438:5;6420:24;:::i;:::-;6415:3;6408:37;6333:118;;:::o;6457:222::-;6550:4;6588:2;6577:9;6573:18;6565:26;;6601:71;6669:1;6658:9;6654:17;6645:6;6601:71;:::i;:::-;6457:222;;;;:::o;6685:117::-;6794:1;6791;6784:12;6808:117;6917:1;6914;6907:12;6931:117;7040:1;7037;7030:12;7068:553;7126:8;7136:6;7186:3;7179:4;7171:6;7167:17;7163:27;7153:122;;7194:79;;:::i;:::-;7153:122;7307:6;7294:20;7284:30;;7337:18;7329:6;7326:30;7323:117;;;7359:79;;:::i;:::-;7323:117;7473:4;7465:6;7461:17;7449:29;;7527:3;7519:4;7511:6;7507:17;7497:8;7493:32;7490:41;7487:128;;;7534:79;;:::i;:::-;7487:128;7068:553;;;;;:::o;7627:529::-;7698:6;7706;7755:2;7743:9;7734:7;7730:23;7726:32;7723:119;;;7761:79;;:::i;:::-;7723:119;7909:1;7898:9;7894:17;7881:31;7939:18;7931:6;7928:30;7925:117;;;7961:79;;:::i;:::-;7925:117;8074:65;8131:7;8122:6;8111:9;8107:22;8074:65;:::i;:::-;8056:83;;;;7852:297;7627:529;;;;;:::o;8179:568::-;8252:8;8262:6;8312:3;8305:4;8297:6;8293:17;8289:27;8279:122;;8320:79;;:::i;:::-;8279:122;8433:6;8420:20;8410:30;;8463:18;8455:6;8452:30;8449:117;;;8485:79;;:::i;:::-;8449:117;8599:4;8591:6;8587:17;8575:29;;8653:3;8645:4;8637:6;8633:17;8623:8;8619:32;8616:41;8613:128;;;8660:79;;:::i;:::-;8613:128;8179:568;;;;;:::o;8753:559::-;8839:6;8847;8896:2;8884:9;8875:7;8871:23;8867:32;8864:119;;;8902:79;;:::i;:::-;8864:119;9050:1;9039:9;9035:17;9022:31;9080:18;9072:6;9069:30;9066:117;;;9102:79;;:::i;:::-;9066:117;9215:80;9287:7;9278:6;9267:9;9263:22;9215:80;:::i;:::-;9197:98;;;;8993:312;8753:559;;;;;:::o;9318:145::-;9416:6;9450:5;9444:12;9434:22;;9318:145;;;:::o;9469:215::-;9599:11;9633:6;9628:3;9621:19;9673:4;9668:3;9664:14;9649:29;;9469:215;;;;:::o;9690:163::-;9788:4;9811:3;9803:11;;9841:4;9836:3;9832:14;9824:22;;9690:163;;;:::o;9859:108::-;9936:24;9954:5;9936:24;:::i;:::-;9931:3;9924:37;9859:108;;:::o;9973:101::-;10009:7;10049:18;10042:5;10038:30;10027:41;;9973:101;;;:::o;10080:105::-;10155:23;10172:5;10155:23;:::i;:::-;10150:3;10143:36;10080:105;;:::o;10191:99::-;10262:21;10277:5;10262:21;:::i;:::-;10257:3;10250:34;10191:99;;:::o;10296:91::-;10332:7;10372:8;10365:5;10361:20;10350:31;;10296:91;;;:::o;10393:105::-;10468:23;10485:5;10468:23;:::i;:::-;10463:3;10456:36;10393:105;;:::o;10576:864::-;10725:4;10720:3;10716:14;10812:4;10805:5;10801:16;10795:23;10831:63;10888:4;10883:3;10879:14;10865:12;10831:63;:::i;:::-;10740:164;10996:4;10989:5;10985:16;10979:23;11015:61;11070:4;11065:3;11061:14;11047:12;11015:61;:::i;:::-;10914:172;11170:4;11163:5;11159:16;11153:23;11189:57;11240:4;11235:3;11231:14;11217:12;11189:57;:::i;:::-;11096:160;11343:4;11336:5;11332:16;11326:23;11362:61;11417:4;11412:3;11408:14;11394:12;11362:61;:::i;:::-;11266:167;10694:746;10576:864;;:::o;11446:303::-;11577:10;11598:108;11702:3;11694:6;11598:108;:::i;:::-;11738:4;11733:3;11729:14;11715:28;;11446:303;;;;:::o;11755:144::-;11856:4;11888;11883:3;11879:14;11871:22;;11755:144;;;:::o;11981:980::-;12162:3;12191:85;12270:5;12191:85;:::i;:::-;12292:117;12402:6;12397:3;12292:117;:::i;:::-;12285:124;;12433:87;12514:5;12433:87;:::i;:::-;12543:7;12574:1;12559:377;12584:6;12581:1;12578:13;12559:377;;;12660:6;12654:13;12687:125;12808:3;12793:13;12687:125;:::i;:::-;12680:132;;12835:91;12919:6;12835:91;:::i;:::-;12825:101;;12619:317;12606:1;12603;12599:9;12594:14;;12559:377;;;12563:14;12952:3;12945:10;;12167:794;;;11981:980;;;;:::o;12967:497::-;13172:4;13210:2;13199:9;13195:18;13187:26;;13259:9;13253:4;13249:20;13245:1;13234:9;13230:17;13223:47;13287:170;13452:4;13443:6;13287:170;:::i;:::-;13279:178;;12967:497;;;;:::o;13487:568::-;13560:8;13570:6;13620:3;13613:4;13605:6;13601:17;13597:27;13587:122;;13628:79;;:::i;:::-;13587:122;13741:6;13728:20;13718:30;;13771:18;13763:6;13760:30;13757:117;;;13793:79;;:::i;:::-;13757:117;13907:4;13899:6;13895:17;13883:29;;13961:3;13953:4;13945:6;13941:17;13931:8;13927:32;13924:41;13921:128;;;13968:79;;:::i;:::-;13921:128;13487:568;;;;;:::o;14061:704::-;14156:6;14164;14172;14221:2;14209:9;14200:7;14196:23;14192:32;14189:119;;;14227:79;;:::i;:::-;14189:119;14347:1;14372:53;14417:7;14408:6;14397:9;14393:22;14372:53;:::i;:::-;14362:63;;14318:117;14502:2;14491:9;14487:18;14474:32;14533:18;14525:6;14522:30;14519:117;;;14555:79;;:::i;:::-;14519:117;14668:80;14740:7;14731:6;14720:9;14716:22;14668:80;:::i;:::-;14650:98;;;;14445:313;14061:704;;;;;:::o;14771:114::-;14838:6;14872:5;14866:12;14856:22;;14771:114;;;:::o;14891:184::-;14990:11;15024:6;15019:3;15012:19;15064:4;15059:3;15055:14;15040:29;;14891:184;;;;:::o;15081:132::-;15148:4;15171:3;15163:11;;15201:4;15196:3;15192:14;15184:22;;15081:132;;;:::o;15219:108::-;15296:24;15314:5;15296:24;:::i;:::-;15291:3;15284:37;15219:108;;:::o;15333:179::-;15402:10;15423:46;15465:3;15457:6;15423:46;:::i;:::-;15501:4;15496:3;15492:14;15478:28;;15333:179;;;;:::o;15518:113::-;15588:4;15620;15615:3;15611:14;15603:22;;15518:113;;;:::o;15667:732::-;15786:3;15815:54;15863:5;15815:54;:::i;:::-;15885:86;15964:6;15959:3;15885:86;:::i;:::-;15878:93;;15995:56;16045:5;15995:56;:::i;:::-;16074:7;16105:1;16090:284;16115:6;16112:1;16109:13;16090:284;;;16191:6;16185:13;16218:63;16277:3;16262:13;16218:63;:::i;:::-;16211:70;;16304:60;16357:6;16304:60;:::i;:::-;16294:70;;16150:224;16137:1;16134;16130:9;16125:14;;16090:284;;;16094:14;16390:3;16383:10;;15791:608;;;15667:732;;;;:::o;16405:373::-;16548:4;16586:2;16575:9;16571:18;16563:26;;16635:9;16629:4;16625:20;16621:1;16610:9;16606:17;16599:47;16663:108;16766:4;16757:6;16663:108;:::i;:::-;16655:116;;16405:373;;;;:::o;16784:704::-;16879:6;16887;16895;16944:2;16932:9;16923:7;16919:23;16915:32;16912:119;;;16950:79;;:::i;:::-;16912:119;17098:1;17087:9;17083:17;17070:31;17128:18;17120:6;17117:30;17114:117;;;17150:79;;:::i;:::-;17114:117;17263:80;17335:7;17326:6;17315:9;17311:22;17263:80;:::i;:::-;17245:98;;;;17041:312;17392:2;17418:53;17463:7;17454:6;17443:9;17439:22;17418:53;:::i;:::-;17408:63;;17363:118;16784:704;;;;;:::o;17494:619::-;17571:6;17579;17587;17636:2;17624:9;17615:7;17611:23;17607:32;17604:119;;;17642:79;;:::i;:::-;17604:119;17762:1;17787:53;17832:7;17823:6;17812:9;17808:22;17787:53;:::i;:::-;17777:63;;17733:117;17889:2;17915:53;17960:7;17951:6;17940:9;17936:22;17915:53;:::i;:::-;17905:63;;17860:118;18017:2;18043:53;18088:7;18079:6;18068:9;18064:22;18043:53;:::i;:::-;18033:63;;17988:118;17494:619;;;;;:::o;18119:116::-;18189:21;18204:5;18189:21;:::i;:::-;18182:5;18179:32;18169:60;;18225:1;18222;18215:12;18169:60;18119:116;:::o;18241:133::-;18284:5;18322:6;18309:20;18300:29;;18338:30;18362:5;18338:30;:::i;:::-;18241:133;;;;:::o;18380:468::-;18445:6;18453;18502:2;18490:9;18481:7;18477:23;18473:32;18470:119;;;18508:79;;:::i;:::-;18470:119;18628:1;18653:53;18698:7;18689:6;18678:9;18674:22;18653:53;:::i;:::-;18643:63;;18599:117;18755:2;18781:50;18823:7;18814:6;18803:9;18799:22;18781:50;:::i;:::-;18771:60;;18726:115;18380:468;;;;;:::o;18854:117::-;18963:1;18960;18953:12;18977:180;19025:77;19022:1;19015:88;19122:4;19119:1;19112:15;19146:4;19143:1;19136:15;19163:281;19246:27;19268:4;19246:27;:::i;:::-;19238:6;19234:40;19376:6;19364:10;19361:22;19340:18;19328:10;19325:34;19322:62;19319:88;;;19387:18;;:::i;:::-;19319:88;19427:10;19423:2;19416:22;19206:238;19163:281;;:::o;19450:129::-;19484:6;19511:20;;:::i;:::-;19501:30;;19540:33;19568:4;19560:6;19540:33;:::i;:::-;19450:129;;;:::o;19585:307::-;19646:4;19736:18;19728:6;19725:30;19722:56;;;19758:18;;:::i;:::-;19722:56;19796:29;19818:6;19796:29;:::i;:::-;19788:37;;19880:4;19874;19870:15;19862:23;;19585:307;;;:::o;19898:154::-;19982:6;19977:3;19972;19959:30;20044:1;20035:6;20030:3;20026:16;20019:27;19898:154;;;:::o;20058:410::-;20135:5;20160:65;20176:48;20217:6;20176:48;:::i;:::-;20160:65;:::i;:::-;20151:74;;20248:6;20241:5;20234:21;20286:4;20279:5;20275:16;20324:3;20315:6;20310:3;20306:16;20303:25;20300:112;;;20331:79;;:::i;:::-;20300:112;20421:41;20455:6;20450:3;20445;20421:41;:::i;:::-;20141:327;20058:410;;;;;:::o;20487:338::-;20542:5;20591:3;20584:4;20576:6;20572:17;20568:27;20558:122;;20599:79;;:::i;:::-;20558:122;20716:6;20703:20;20741:78;20815:3;20807:6;20800:4;20792:6;20788:17;20741:78;:::i;:::-;20732:87;;20548:277;20487:338;;;;:::o;20831:943::-;20926:6;20934;20942;20950;20999:3;20987:9;20978:7;20974:23;20970:33;20967:120;;;21006:79;;:::i;:::-;20967:120;21126:1;21151:53;21196:7;21187:6;21176:9;21172:22;21151:53;:::i;:::-;21141:63;;21097:117;21253:2;21279:53;21324:7;21315:6;21304:9;21300:22;21279:53;:::i;:::-;21269:63;;21224:118;21381:2;21407:53;21452:7;21443:6;21432:9;21428:22;21407:53;:::i;:::-;21397:63;;21352:118;21537:2;21526:9;21522:18;21509:32;21568:18;21560:6;21557:30;21554:117;;;21590:79;;:::i;:::-;21554:117;21695:62;21749:7;21740:6;21729:9;21725:22;21695:62;:::i;:::-;21685:72;;21480:287;20831:943;;;;;;;:::o;21852:874::-;22011:4;22006:3;22002:14;22098:4;22091:5;22087:16;22081:23;22117:63;22174:4;22169:3;22165:14;22151:12;22117:63;:::i;:::-;22026:164;22282:4;22275:5;22271:16;22265:23;22301:61;22356:4;22351:3;22347:14;22333:12;22301:61;:::i;:::-;22200:172;22456:4;22449:5;22445:16;22439:23;22475:57;22526:4;22521:3;22517:14;22503:12;22475:57;:::i;:::-;22382:160;22629:4;22622:5;22618:16;22612:23;22648:61;22703:4;22698:3;22694:14;22680:12;22648:61;:::i;:::-;22552:167;21980:746;21852:874;;:::o;22732:347::-;22887:4;22925:3;22914:9;22910:19;22902:27;;22939:133;23069:1;23058:9;23054:17;23045:6;22939:133;:::i;:::-;22732:347;;;;:::o;23085:474::-;23153:6;23161;23210:2;23198:9;23189:7;23185:23;23181:32;23178:119;;;23216:79;;:::i;:::-;23178:119;23336:1;23361:53;23406:7;23397:6;23386:9;23382:22;23361:53;:::i;:::-;23351:63;;23307:117;23463:2;23489:53;23534:7;23525:6;23514:9;23510:22;23489:53;:::i;:::-;23479:63;;23434:118;23085:474;;;;;:::o;23565:162::-;23705:14;23701:1;23693:6;23689:14;23682:38;23565:162;:::o;23733:366::-;23875:3;23896:67;23960:2;23955:3;23896:67;:::i;:::-;23889:74;;23972:93;24061:3;23972:93;:::i;:::-;24090:2;24085:3;24081:12;24074:19;;23733:366;;;:::o;24105:419::-;24271:4;24309:2;24298:9;24294:18;24286:26;;24358:9;24352:4;24348:20;24344:1;24333:9;24329:17;24322:47;24386:131;24512:4;24386:131;:::i;:::-;24378:139;;24105:419;;;:::o;24530:164::-;24670:16;24666:1;24658:6;24654:14;24647:40;24530:164;:::o;24700:366::-;24842:3;24863:67;24927:2;24922:3;24863:67;:::i;:::-;24856:74;;24939:93;25028:3;24939:93;:::i;:::-;25057:2;25052:3;25048:12;25041:19;;24700:366;;;:::o;25072:419::-;25238:4;25276:2;25265:9;25261:18;25253:26;;25325:9;25319:4;25315:20;25311:1;25300:9;25296:17;25289:47;25353:131;25479:4;25353:131;:::i;:::-;25345:139;;25072:419;;;:::o;25497:180::-;25545:77;25542:1;25535:88;25642:4;25639:1;25632:15;25666:4;25663:1;25656:15;25683:320;25727:6;25764:1;25758:4;25754:12;25744:22;;25811:1;25805:4;25801:12;25832:18;25822:81;;25888:4;25880:6;25876:17;25866:27;;25822:81;25950:2;25942:6;25939:14;25919:18;25916:38;25913:84;;25969:18;;:::i;:::-;25913:84;25734:269;25683:320;;;:::o;26009:332::-;26130:4;26168:2;26157:9;26153:18;26145:26;;26181:71;26249:1;26238:9;26234:17;26225:6;26181:71;:::i;:::-;26262:72;26330:2;26319:9;26315:18;26306:6;26262:72;:::i;:::-;26009:332;;;;;:::o;26347:137::-;26401:5;26432:6;26426:13;26417:22;;26448:30;26472:5;26448:30;:::i;:::-;26347:137;;;;:::o;26490:345::-;26557:6;26606:2;26594:9;26585:7;26581:23;26577:32;26574:119;;;26612:79;;:::i;:::-;26574:119;26732:1;26757:61;26810:7;26801:6;26790:9;26786:22;26757:61;:::i;:::-;26747:71;;26703:125;26490:345;;;;:::o;26841:162::-;26981:14;26977:1;26969:6;26965:14;26958:38;26841:162;:::o;27009:366::-;27151:3;27172:67;27236:2;27231:3;27172:67;:::i;:::-;27165:74;;27248:93;27337:3;27248:93;:::i;:::-;27366:2;27361:3;27357:12;27350:19;;27009:366;;;:::o;27381:419::-;27547:4;27585:2;27574:9;27570:18;27562:26;;27634:9;27628:4;27624:20;27620:1;27609:9;27605:17;27598:47;27662:131;27788:4;27662:131;:::i;:::-;27654:139;;27381:419;;;:::o;27806:180::-;27854:77;27851:1;27844:88;27951:4;27948:1;27941:15;27975:4;27972:1;27965:15;27992:164;28132:16;28128:1;28120:6;28116:14;28109:40;27992:164;:::o;28162:366::-;28304:3;28325:67;28389:2;28384:3;28325:67;:::i;:::-;28318:74;;28401:93;28490:3;28401:93;:::i;:::-;28519:2;28514:3;28510:12;28503:19;;28162:366;;;:::o;28534:419::-;28700:4;28738:2;28727:9;28723:18;28715:26;;28787:9;28781:4;28777:20;28773:1;28762:9;28758:17;28751:47;28815:131;28941:4;28815:131;:::i;:::-;28807:139;;28534:419;;;:::o;28959:164::-;29099:16;29095:1;29087:6;29083:14;29076:40;28959:164;:::o;29129:366::-;29271:3;29292:67;29356:2;29351:3;29292:67;:::i;:::-;29285:74;;29368:93;29457:3;29368:93;:::i;:::-;29486:2;29481:3;29477:12;29470:19;;29129:366;;;:::o;29501:419::-;29667:4;29705:2;29694:9;29690:18;29682:26;;29754:9;29748:4;29744:20;29740:1;29729:9;29725:17;29718:47;29782:131;29908:4;29782:131;:::i;:::-;29774:139;;29501:419;;;:::o;29926:181::-;30066:33;30062:1;30054:6;30050:14;30043:57;29926:181;:::o;30113:366::-;30255:3;30276:67;30340:2;30335:3;30276:67;:::i;:::-;30269:74;;30352:93;30441:3;30352:93;:::i;:::-;30470:2;30465:3;30461:12;30454:19;;30113:366;;;:::o;30485:419::-;30651:4;30689:2;30678:9;30674:18;30666:26;;30738:9;30732:4;30728:20;30724:1;30713:9;30709:17;30702:47;30766:131;30892:4;30766:131;:::i;:::-;30758:139;;30485:419;;;:::o;30910:169::-;31050:21;31046:1;31038:6;31034:14;31027:45;30910:169;:::o;31085:366::-;31227:3;31248:67;31312:2;31307:3;31248:67;:::i;:::-;31241:74;;31324:93;31413:3;31324:93;:::i;:::-;31442:2;31437:3;31433:12;31426:19;;31085:366;;;:::o;31457:419::-;31623:4;31661:2;31650:9;31646:18;31638:26;;31710:9;31704:4;31700:20;31696:1;31685:9;31681:17;31674:47;31738:131;31864:4;31738:131;:::i;:::-;31730:139;;31457:419;;;:::o;31882:168::-;32022:20;32018:1;32010:6;32006:14;31999:44;31882:168;:::o;32056:366::-;32198:3;32219:67;32283:2;32278:3;32219:67;:::i;:::-;32212:74;;32295:93;32384:3;32295:93;:::i;:::-;32413:2;32408:3;32404:12;32397:19;;32056:366;;;:::o;32428:419::-;32594:4;32632:2;32621:9;32617:18;32609:26;;32681:9;32675:4;32671:20;32667:1;32656:9;32652:17;32645:47;32709:131;32835:4;32709:131;:::i;:::-;32701:139;;32428:419;;;:::o;32853:170::-;32993:22;32989:1;32981:6;32977:14;32970:46;32853:170;:::o;33029:366::-;33171:3;33192:67;33256:2;33251:3;33192:67;:::i;:::-;33185:74;;33268:93;33357:3;33268:93;:::i;:::-;33386:2;33381:3;33377:12;33370:19;;33029:366;;;:::o;33401:419::-;33567:4;33605:2;33594:9;33590:18;33582:26;;33654:9;33648:4;33644:20;33640:1;33629:9;33625:17;33618:47;33682:131;33808:4;33682:131;:::i;:::-;33674:139;;33401:419;;;:::o;33826:94::-;33859:8;33907:5;33903:2;33899:14;33878:35;;33826:94;;;:::o;33926:::-;33965:7;33994:20;34008:5;33994:20;:::i;:::-;33983:31;;33926:94;;;:::o;34026:100::-;34065:7;34094:26;34114:5;34094:26;:::i;:::-;34083:37;;34026:100;;;:::o;34132:157::-;34237:45;34257:24;34275:5;34257:24;:::i;:::-;34237:45;:::i;:::-;34232:3;34225:58;34132:157;;:::o;34295:79::-;34334:7;34363:5;34352:16;;34295:79;;;:::o;34380:157::-;34485:45;34505:24;34523:5;34505:24;:::i;:::-;34485:45;:::i;:::-;34480:3;34473:58;34380:157;;:::o;34543:397::-;34683:3;34698:75;34769:3;34760:6;34698:75;:::i;:::-;34798:2;34793:3;34789:12;34782:19;;34811:75;34882:3;34873:6;34811:75;:::i;:::-;34911:2;34906:3;34902:12;34895:19;;34931:3;34924:10;;34543:397;;;;;:::o;34946:148::-;35048:11;35085:3;35070:18;;34946:148;;;;:::o;35100:377::-;35206:3;35234:39;35267:5;35234:39;:::i;:::-;35289:89;35371:6;35366:3;35289:89;:::i;:::-;35282:96;;35387:52;35432:6;35427:3;35420:4;35413:5;35409:16;35387:52;:::i;:::-;35464:6;35459:3;35455:16;35448:23;;35210:267;35100:377;;;;:::o;35483:435::-;35663:3;35685:95;35776:3;35767:6;35685:95;:::i;:::-;35678:102;;35797:95;35888:3;35879:6;35797:95;:::i;:::-;35790:102;;35909:3;35902:10;;35483:435;;;;;:::o;35924:180::-;35972:77;35969:1;35962:88;36069:4;36066:1;36059:15;36093:4;36090:1;36083:15;36110:233;36149:3;36172:24;36190:5;36172:24;:::i;:::-;36163:33;;36218:66;36211:5;36208:77;36205:103;;36288:18;;:::i;:::-;36205:103;36335:1;36328:5;36324:13;36317:20;;36110:233;;;:::o;36349:98::-;36400:6;36434:5;36428:12;36418:22;;36349:98;;;:::o;36453:168::-;36536:11;36570:6;36565:3;36558:19;36610:4;36605:3;36601:14;36586:29;;36453:168;;;;:::o;36627:360::-;36713:3;36741:38;36773:5;36741:38;:::i;:::-;36795:70;36858:6;36853:3;36795:70;:::i;:::-;36788:77;;36874:52;36919:6;36914:3;36907:4;36900:5;36896:16;36874:52;:::i;:::-;36951:29;36973:6;36951:29;:::i;:::-;36946:3;36942:39;36935:46;;36717:270;36627:360;;;;:::o;36993:640::-;37188:4;37226:3;37215:9;37211:19;37203:27;;37240:71;37308:1;37297:9;37293:17;37284:6;37240:71;:::i;:::-;37321:72;37389:2;37378:9;37374:18;37365:6;37321:72;:::i;:::-;37403;37471:2;37460:9;37456:18;37447:6;37403:72;:::i;:::-;37522:9;37516:4;37512:20;37507:2;37496:9;37492:18;37485:48;37550:76;37621:4;37612:6;37550:76;:::i;:::-;37542:84;;36993:640;;;;;;;:::o;37639:141::-;37695:5;37726:6;37720:13;37711:22;;37742:32;37768:5;37742:32;:::i;:::-;37639:141;;;;:::o;37786:349::-;37855:6;37904:2;37892:9;37883:7;37879:23;37875:32;37872:119;;;37910:79;;:::i;:::-;37872:119;38030:1;38055:63;38110:7;38101:6;38090:9;38086:22;38055:63;:::i;:::-;38045:73;;38001:127;37786:349;;;;:::o

Swarm Source

ipfs://5fa18252be9c00bebf740c7643df3691b882bb18c8e3afd3a4c0b5c7eb1965a6
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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