ETH Price: $3,362.04 (-3.22%)

Token

Whoopsies (WHOOP)
 

Overview

Max Total Supply

3,440 WHOOP

Holders

439

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
coger.eth
Balance
5 WHOOP
0xb2dc5b8a6c984fdc87f1fbac53e01770bbdf9326
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Community centered Project . Artwork by Kentasi Studio

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Whoopsies

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-08-31
*/

// SPDX-License-Identifier: MIT

/// @title ERC721 Implementation of Whoopsies v2 Collection
/// @custom:security-contact [email protected]
/// @author Shehroz K. | Captain Unknown (@captainunknown5)

// File: lib/Constants.sol


pragma solidity ^0.8.13;

address constant CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS = 0x000000000000AAeB6D7670E522A718067333cd4E;
address constant CANONICAL_CORI_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6;

// File: IOperatorFilterRegistry.sol


pragma solidity ^0.8.13;

interface IOperatorFilterRegistry {
    /**
     * @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns
     *         true if supplied registrant address is not registered.
     */
    function isOperatorAllowed(address registrant, address operator) external view returns (bool);

    /**
     * @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner.
     */
    function register(address registrant) external;

    /**
     * @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes.
     */
    function registerAndSubscribe(address registrant, address subscription) external;

    /**
     * @notice Registers an address with the registry and copies the filtered operators and codeHashes from another
     *         address without subscribing.
     */
    function registerAndCopyEntries(address registrant, address registrantToCopy) external;

    /**
     * @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner.
     *         Note that this does not remove any filtered addresses or codeHashes.
     *         Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes.
     */
    function unregister(address addr) external;

    /**
     * @notice Update an operator address for a registered address - when filtered is true, the operator is filtered.
     */
    function updateOperator(address registrant, address operator, bool filtered) external;

    /**
     * @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates.
     */
    function updateOperators(address registrant, address[] calldata operators, bool filtered) external;

    /**
     * @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered.
     */
    function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external;

    /**
     * @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates.
     */
    function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external;

    /**
     * @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous
     *         subscription if present.
     *         Note that accounts with subscriptions may go on to subscribe to other accounts - in this case,
     *         subscriptions will not be forwarded. Instead the former subscription's existing entries will still be
     *         used.
     */
    function subscribe(address registrant, address registrantToSubscribe) external;

    /**
     * @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes.
     */
    function unsubscribe(address registrant, bool copyExistingEntries) external;

    /**
     * @notice Get the subscription address of a given registrant, if any.
     */
    function subscriptionOf(address addr) external returns (address registrant);

    /**
     * @notice Get the set of addresses subscribed to a given registrant.
     *         Note that order is not guaranteed as updates are made.
     */
    function subscribers(address registrant) external returns (address[] memory);

    /**
     * @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant.
     *         Note that order is not guaranteed as updates are made.
     */
    function subscriberAt(address registrant, uint256 index) external returns (address);

    /**
     * @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr.
     */
    function copyEntriesOf(address registrant, address registrantToCopy) external;

    /**
     * @notice Returns true if operator is filtered by a given address or its subscription.
     */
    function isOperatorFiltered(address registrant, address operator) external returns (bool);

    /**
     * @notice Returns true if the hash of an address's code is filtered by a given address or its subscription.
     */
    function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);

    /**
     * @notice Returns true if a codeHash is filtered by a given address or its subscription.
     */
    function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);

    /**
     * @notice Returns a list of filtered operators for a given address or its subscription.
     */
    function filteredOperators(address addr) external returns (address[] memory);

    /**
     * @notice Returns the set of filtered codeHashes for a given address or its subscription.
     *         Note that order is not guaranteed as updates are made.
     */
    function filteredCodeHashes(address addr) external returns (bytes32[] memory);

    /**
     * @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or
     *         its subscription.
     *         Note that order is not guaranteed as updates are made.
     */
    function filteredOperatorAt(address registrant, uint256 index) external returns (address);

    /**
     * @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or
     *         its subscription.
     *         Note that order is not guaranteed as updates are made.
     */
    function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);

    /**
     * @notice Returns true if an address has registered
     */
    function isRegistered(address addr) external returns (bool);

    /**
     * @dev Convenience method to compute the code hash of an arbitrary contract
     */
    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.
 * @dev    This smart contract is meant to be inherited by token contracts so they can use the following:
 *         - `onlyAllowedOperator` modifier for `transferFrom` and `safeTransferFrom` methods.
 *         - `onlyAllowedOperatorApproval` modifier for `approve` and `setApprovalForAll` methods.
 *         Please note that if your token contract does not provide an owner with EIP-173, it must provide
 *         administration methods on the contract itself to interact with the registry otherwise the subscription
 *         will be locked to the options set during construction.
 */

abstract contract OperatorFilterer {
    /// @dev Emitted when an operator is not allowed.
    error OperatorNotAllowed(address operator);

    IOperatorFilterRegistry public constant OPERATOR_FILTER_REGISTRY =
        IOperatorFilterRegistry(CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS);

    /// @dev The constructor that is called when the contract is being deployed.
    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));
                }
            }
        }
    }

    /**
     * @dev A helper function to check if an operator is allowed.
     */
    modifier onlyAllowedOperator(address from) virtual {
        // 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) {
            _checkFilterOperator(msg.sender);
        }
        _;
    }

    /**
     * @dev A helper function to check if an operator approval is allowed.
     */
    modifier onlyAllowedOperatorApproval(address operator) virtual {
        _checkFilterOperator(operator);
        _;
    }

    /**
     * @dev A helper function to check if an operator is allowed.
     */
    function _checkFilterOperator(address operator) internal view virtual {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
            // under normal circumstances, this function will revert rather than return false, but inheriting contracts
            // may specify their own OperatorFilterRegistry implementations, which may behave differently
            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.
 * @dev    Please note that if your token contract does not provide an owner with EIP-173, it must provide
 *         administration methods on the contract itself to interact with the registry otherwise the subscription
 *         will be locked to the options set during construction.
 */

abstract contract DefaultOperatorFilterer is OperatorFilterer {
    /// @dev The constructor that is called when the contract is being deployed.
    constructor() OperatorFilterer(CANONICAL_CORI_SUBSCRIPTION, true) {}
}

// File: SoladyOwnable.sol


pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

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

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

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

    /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Store the new value.
            sstore(not(_OWNER_SLOT_NOT), newOwner)
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let ownerSlot := not(_OWNER_SLOT_NOT)
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
            // Store the new value.
            sstore(ownerSlot, newOwner)
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(not(_OWNER_SLOT_NOT))
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

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

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}
// File: @openzeppelin/contracts/utils/math/SignedMath.sol


// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

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

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

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

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

// File: @openzeppelin/contracts/utils/math/Math.sol


// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

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

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

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

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

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

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

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

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

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

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// File: @openzeppelin/contracts/utils/Strings.sol


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

pragma solidity ^0.8.0;



/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _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) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

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

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

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        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] = _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);
    }

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

// File: @openzeppelin/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: @openzeppelin/contracts/utils/Address.sol


// OpenZeppelin Contracts (last updated v4.9.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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [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://consensys.net/diligence/blog/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.8.0/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: @openzeppelin/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: @openzeppelin/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: @openzeppelin/contracts/interfaces/IERC165.sol


// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)

pragma solidity ^0.8.0;


// File: @openzeppelin/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: @openzeppelin/contracts/token/ERC721/IERC721.sol


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

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

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the 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: @openzeppelin/contracts/interfaces/IERC721.sol


// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol)

pragma solidity ^0.8.0;


// File: @openzeppelin/contracts/interfaces/IERC4906.sol


// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4906.sol)

pragma solidity ^0.8.0;



/// @title EIP-721 Metadata Update Extension
interface IERC4906 is IERC165, IERC721 {
    /// @dev This event emits when the metadata of a token is changed.
    /// So that the third-party platforms such as NFT market could
    /// timely update the images and related attributes of the NFT.
    event MetadataUpdate(uint256 _tokenId);

    /// @dev This event emits when the metadata of a range of tokens is changed.
    /// So that the third-party platforms such as NFT market could
    /// timely update the images and related attributes of the NFTs.
    event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}

// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol


// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;


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

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

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

// File: @openzeppelin/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: @openzeppelin/contracts/token/ERC721/ERC721.sol


// OpenZeppelin Contracts (last updated v4.9.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 = _ownerOf(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 the owner of the `tokenId`. Does NOT revert if token doesn't exist
     */
    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
        return _owners[tokenId];
    }

    /**
     * @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 _ownerOf(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, 1);

        // 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, 1);
    }

    /**
     * @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, 1);

        // 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, 1);
    }

    /**
     * @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, 1);

        // 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, 1);
    }

    /**
     * @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. If {ERC721Consecutive} is
     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
     * - When `from` is zero, the tokens will be minted for `to`.
     * - When `to` is zero, ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     * - `batchSize` is non-zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}

    /**
     * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
     * - When `from` is zero, the tokens were minted for `to`.
     * - When `to` is zero, ``from``'s tokens were burned.
     * - `from` and `to` are never both zero.
     * - `batchSize` is non-zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}

    /**
     * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
     *
     * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant
     * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such
     * that `ownerOf(tokenId)` is `a`.
     */
    // solhint-disable-next-line func-name-mixedcase
    function __unsafe_increaseBalance(address account, uint256 amount) internal {
        _balances[account] += amount;
    }
}

// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol


// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/extensions/ERC721URIStorage.sol)

pragma solidity ^0.8.0;



/**
 * @dev ERC721 token with storage based token URI management.
 */
abstract contract ERC721URIStorage is IERC4906, ERC721 {
    using Strings for uint256;

    // Optional mapping for token URIs
    mapping(uint256 => string) private _tokenURIs;

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

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

        string memory _tokenURI = _tokenURIs[tokenId];
        string memory base = _baseURI();

        // If there is no base URI, return the token URI.
        if (bytes(base).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(base, _tokenURI));
        }

        return super.tokenURI(tokenId);
    }

    /**
     * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
     *
     * Emits {MetadataUpdate}.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
        require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
        _tokenURIs[tokenId] = _tokenURI;

        emit MetadataUpdate(tokenId);
    }

    /**
     * @dev See {ERC721-_burn}. This override additionally checks to see if a
     * token-specific URI was set for the token, and if so, it deletes the token URI from
     * the storage mapping.
     */
    function _burn(uint256 tokenId) internal virtual override {
        super._burn(tokenId);

        if (bytes(_tokenURIs[tokenId]).length != 0) {
            delete _tokenURIs[tokenId];
        }
    }
}

// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol


// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol)

pragma solidity ^0.8.0;



/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
 * enumerability of all the token ids in the contract as well as all token ids owned by each
 * account.
 */
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

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

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

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

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev See {ERC721-_beforeTokenTransfer}.
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 firstTokenId,
        uint256 batchSize
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);

        if (batchSize > 1) {
            // Will only trigger during construction. Batch transferring (minting) is not available afterwards.
            revert("ERC721Enumerable: consecutive transfers not supported");
        }

        uint256 tokenId = firstTokenId;

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

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

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

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

        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

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

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

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

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

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

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

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

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

// File: WhoopsiesAudited.sol



/// @title ERC721 Implementation of Whoopsies v2 Collection
pragma solidity ^0.8.9;







interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
}

// Errors
error NotOwner();
error NotActive();
error invalidValue();
error ClaimNotActive();
error TransferFailed();
error ZeroClaimable();
error CoolDownActive();

/// @custom:security-contact [email protected]
contract Whoopsies is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable, DefaultOperatorFilterer {
    address public constant whoopsiesV1 = 0x565AbC3FEaa3bC3820B83620f4BbF16B5c4D47a3;
    bool public v2ClaimActive = false;
    bool public doopClaimActive = false;
    string public baseUri = "ipfs://QmYJGEoa3zRNMVFLsRcgzXNNQ3g2HsQQeipSLFstivW4hB/";
    string public constant baseExtension = ".json";
    uint256 public immutable initialTime;
    uint256 public claimPrice;
    IERC20 public doopToken;
    
    mapping (address => uint256) public totalClaimed;
    mapping (address => uint256) public lastDoopClaimTime;

    constructor() ERC721("Whoopsies", "WHOOP") {
        _initializeOwner(msg.sender);
        initialTime = block.timestamp;
    }

    /// @notice Transfers v2 equivalent old collection to the caller
    /// @param requestedTokenIds TokenID(s) to claim
    function claimV2NFTs(uint256[] calldata requestedTokenIds) public payable {
        if (!v2ClaimActive) revert NotActive();
        if (requestedTokenIds.length * claimPrice != msg.value) revert invalidValue();
        for (uint256 i; i < requestedTokenIds.length;) {
            if (IERC721(whoopsiesV1).ownerOf(requestedTokenIds[i]) != msg.sender) revert NotOwner();
            _safeMint(msg.sender, requestedTokenIds[i]);
            unchecked {
                i++;
            }
        }
    }

    /// @notice Transfers claimable Doop to the caller
    function claimDoop() public {
        if (!doopClaimActive) revert ClaimNotActive();
        uint256 balance = balanceOf(_msgSender());
        if (balance == 0) revert ZeroClaimable();
        
        uint256 claimablePerNFT;
        uint256 previous = lastDoopClaimTime[msg.sender];
        uint256 timestamp = block.timestamp;

        if (previous != 0) {
            if (previous + 1 days > timestamp) revert CoolDownActive();
            claimablePerNFT = ((timestamp - previous) / 1 days) * 5;
        } else {
            claimablePerNFT = ((timestamp - initialTime) / 1 days) * 5;
        }

        lastDoopClaimTime[msg.sender] = timestamp;
        uint256 totalClaimable = claimablePerNFT * balance;
        unchecked {
            totalClaimed[msg.sender] += totalClaimable;
        }

        if (!doopToken.transfer(msg.sender, totalClaimable * 10 ** 18)) revert TransferFailed();
    }
    
    /// @notice Retrieves Doop tokens available to claim for the given address
    /// @param _address The address to query claimable Doop tokens for
    /// @return Amount of claimable Doop tokens
    function retrieveClaimableDoop(address _address) public view returns (uint256) {
        uint256 balance = balanceOf(_msgSender());
        uint256 timestamp = block.timestamp;
        if (balance == 0) return 0;
        uint256 claimablePerNFT;
        uint256 pTime = lastDoopClaimTime[_address];
        if (pTime != 0) claimablePerNFT = ((timestamp - pTime) / 1 days) * 5;
        else claimablePerNFT = ((timestamp - initialTime) / 1 days) * 5;

        uint256 claimable = claimablePerNFT * balance;
        return claimable * 10 ** 18;
    }

    // Utils
    /// @notice Toggle v2 NFTs claim eligibility state
    function toggleV2ClaimActive() public onlyOwner {
        v2ClaimActive = !v2ClaimActive;
    }

    /// @notice Toggle Doop Tokens claim eligibility state
    function toggleDoopClaimActive() public onlyOwner {
        doopClaimActive = !doopClaimActive;
    }

    /// @notice Changes Doop Token address to the given address
    /// @param _tokenAddress Address to change the Doop token address to
    function setDoopAddress(address _tokenAddress) public onlyOwner {
        doopToken = IERC20(_tokenAddress);
    }

    /// @notice Changes claim price to the given price
    /// @param newClaimPrice The new claim price for single claim
    function setClaimPrice(uint256 newClaimPrice) public onlyOwner {
        claimPrice = newClaimPrice;
    }

    // The following functions are operator filterer overrides.
    function setApprovalForAll(address operator, bool approved) public override(ERC721, IERC721) onlyAllowedOperatorApproval(operator) {
        super.setApprovalForAll(operator, approved);
    }
    
    function approve(address operator, uint256 tokenId) public override(ERC721, IERC721) onlyAllowedOperatorApproval(operator) {
        super.approve(operator, tokenId);
    }
    
    function transferFrom(address from, address to, uint256 tokenId) public override(ERC721, IERC721) onlyAllowedOperator(from) {
        super.transferFrom(from, to, tokenId);
    }

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

    // The following functions are overrides required by Solidity.
    function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId, batchSize);
    }

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    /// @notice Changes token base URI to the given string
    /// @param _newBaseURI URI to change the base URI to
    function setBaseURI(string memory _newBaseURI) public onlyOwner {
        baseUri = _newBaseURI;
    }

    /// @return Current Base URI
    function _baseURI() internal view override returns (string memory) {
        return baseUri;
    }

    /// @param tokenId TokenID to retrieve URI for
    /// @return Current URI for the given tokenId
    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return string(abi.encodePacked(_baseURI(), Strings.toString(tokenId), baseExtension));
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable, ERC721URIStorage)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    /// @notice Withdraws given amount of Doop Tokens
    /// @param amount Amount of Doop token to withdraw
    function withdrawDoop(uint256 amount) public onlyOwner {
        doopToken.transfer(msg.sender, amount);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ClaimNotActive","type":"error"},{"inputs":[],"name":"CoolDownActive","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotActive","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroClaimable","type":"error"},{"inputs":[],"name":"invalidValue","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":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"OPERATOR_FILTER_REGISTRY","outputs":[{"internalType":"contract IOperatorFilterRegistry","name":"","type":"address"}],"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":[],"name":"baseExtension","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseUri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimDoop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"requestedTokenIds","type":"uint256[]"}],"name":"claimV2NFTs","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"doopClaimActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"doopToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastDoopClaimTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"retrieveClaimableDoop","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newClaimPrice","type":"uint256"}],"name":"setClaimPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"setDoopAddress","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":[],"name":"toggleDoopClaimActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleV2ClaimActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalClaimed","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":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"v2ClaimActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whoopsiesV1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawDoop","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040525f600b5f6101000a81548160ff0219169083151502179055505f600b60016101000a81548160ff02191690831515021790555060405180606001604052806036815260200162004d8e60369139600c9081620000619190620005ba565b503480156200006e575f80fd5b50733cc6cdda760b79bafa08df41ecfa224f810dceb660016040518060400160405280600981526020017f57686f6f707369657300000000000000000000000000000000000000000000008152506040518060400160405280600581526020017f57484f4f50000000000000000000000000000000000000000000000000000000815250815f9081620001029190620005ba565b508060019081620001149190620005ba565b5050505f6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115620002fb578015620001cc576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff16637d3e3dbe30846040518363ffffffff1660e01b815260040162000197929190620006e1565b5f604051808303815f87803b158015620001af575f80fd5b505af1158015620001c2573d5f803e3d5ffd5b50505050620002fa565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161462000280576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663a0af290330846040518363ffffffff1660e01b81526004016200024b929190620006e1565b5f604051808303815f87803b15801562000263575f80fd5b505af115801562000276573d5f803e3d5ffd5b50505050620002f9565b6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff16634420e486306040518263ffffffff1660e01b8152600401620002c991906200070c565b5f604051808303815f87803b158015620002e1575f80fd5b505af1158015620002f4573d5f803e3d5ffd5b505050505b5b5b50506200030e336200031c60201b60201c565b426080818152505062000727565b8060601b60601c905080638b78c6d81955805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a350565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003d257607f821691505b602082108103620003e857620003e76200038d565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026200044c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200040f565b6200045886836200040f565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620004a26200049c620004968462000470565b62000479565b62000470565b9050919050565b5f819050919050565b620004bd8362000482565b620004d5620004cc82620004a9565b8484546200041b565b825550505050565b5f90565b620004eb620004dd565b620004f8818484620004b2565b505050565b5b818110156200051f57620005135f82620004e1565b600181019050620004fe565b5050565b601f8211156200056e576200053881620003ee565b620005438462000400565b8101602085101562000553578190505b6200056b620005628562000400565b830182620004fd565b50505b505050565b5f82821c905092915050565b5f620005905f198460080262000573565b1980831691505092915050565b5f620005aa83836200057f565b9150826002028217905092915050565b620005c58262000356565b67ffffffffffffffff811115620005e157620005e062000360565b5b620005ed8254620003ba565b620005fa82828562000523565b5f60209050601f83116001811462000630575f84156200061b578287015190505b6200062785826200059d565b86555062000696565b601f1984166200064086620003ee565b5f5b82811015620006695784890151825560018201915060208501945060208101905062000642565b8683101562000689578489015162000685601f8916826200057f565b8355505b6001600288020188555050505b505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f620006c9826200069e565b9050919050565b620006db81620006bd565b82525050565b5f604082019050620006f65f830185620006d0565b620007056020830184620006d0565b9392505050565b5f602082019050620007215f830184620006d0565b92915050565b6080516146406200074e5f395f81816110de015281816115f8015261180b01526146405ff3fe60806040526004361061025b575f3560e01c80636352211e11610143578063c60360f7116100b5578063e985e9c511610079578063e985e9c514610845578063eca30a4114610881578063ef5d9ae8146108bd578063f04e283e146108f9578063f2fde38b14610915578063fee81cf4146109315761025b565b8063c60360f71461074f578063c668286214610779578063c67c74d4146107a3578063c87b56dd146107cd578063e5267d17146108095761025b565b80638da5cb5b116101075780638da5cb5b1461065757806395d89b41146106815780639abc8320146106ab5780639ced0e9b146106d5578063a22cb465146106ff578063b88d4fde146107275761025b565b80636352211e1461059757806370a08231146105d3578063715018a61461060f5780637e082c16146106195780638c1ceda51461062f5761025b565b80632f745c59116101dc57806342842e0e116101a057806342842e0e146104c35780634f6ccce7146104eb57806351f468c01461052757806354d1f13d1461054f57806355f804b3146105595780635e08dff6146105815761025b565b80632f745c59146104015780633745ee951461043d578063381b1e5d14610467578063398280eb1461048357806341f43434146104995761025b565b806315d655c91161022357806315d655c91461035357806317d819d01461037d57806318160ddd146103a557806323b872dd146103cf57806325692962146103f75761025b565b806301ffc9a71461025f57806306fdde031461029b578063081812fc146102c557806308e0415814610301578063095ea7b31461032b575b5f80fd5b34801561026a575f80fd5b506102856004803603810190610280919061312d565b61096d565b6040516102929190613172565b60405180910390f35b3480156102a6575f80fd5b506102af61097e565b6040516102bc9190613215565b60405180910390f35b3480156102d0575f80fd5b506102eb60048036038101906102e69190613268565b610a0d565b6040516102f891906132d2565b60405180910390f35b34801561030c575f80fd5b50610315610a4f565b6040516103229190613346565b60405180910390f35b348015610336575f80fd5b50610351600480360381019061034c9190613389565b610a74565b005b34801561035e575f80fd5b50610367610a8d565b60405161037491906133d6565b60405180910390f35b348015610388575f80fd5b506103a3600480360381019061039e91906133ef565b610a93565b005b3480156103b0575f80fd5b506103b9610ade565b6040516103c691906133d6565b60405180910390f35b3480156103da575f80fd5b506103f560048036038101906103f0919061341a565b610aea565b005b6103ff610b39565b005b34801561040c575f80fd5b5061042760048036038101906104229190613389565b610b8a565b60405161043491906133d6565b60405180910390f35b348015610448575f80fd5b50610451610c2a565b60405161045e91906132d2565b60405180910390f35b610481600480360381019061047c91906134cb565b610c42565b005b34801561048e575f80fd5b50610497610e1b565b005b3480156104a4575f80fd5b506104ad610e4d565b6040516104ba9190613536565b60405180910390f35b3480156104ce575f80fd5b506104e960048036038101906104e4919061341a565b610e5f565b005b3480156104f6575f80fd5b50610511600480360381019061050c9190613268565b610eae565b60405161051e91906133d6565b60405180910390f35b348015610532575f80fd5b5061054d60048036038101906105489190613268565b610f1c565b005b610557610f2e565b005b348015610564575f80fd5b5061057f600480360381019061057a9190613677565b610f67565b005b34801561058c575f80fd5b50610595610f82565b005b3480156105a2575f80fd5b506105bd60048036038101906105b89190613268565b6112a6565b6040516105ca91906132d2565b60405180910390f35b3480156105de575f80fd5b506105f960048036038101906105f491906133ef565b61132a565b60405161060691906133d6565b60405180910390f35b6106176113de565b005b348015610624575f80fd5b5061062d6113f1565b005b34801561063a575f80fd5b5061065560048036038101906106509190613268565b611425565b005b348015610662575f80fd5b5061066b6114cd565b60405161067891906132d2565b60405180910390f35b34801561068c575f80fd5b506106956114da565b6040516106a29190613215565b60405180910390f35b3480156106b6575f80fd5b506106bf61156a565b6040516106cc9190613215565b60405180910390f35b3480156106e0575f80fd5b506106e96115f6565b6040516106f691906133d6565b60405180910390f35b34801561070a575f80fd5b50610725600480360381019061072091906136e8565b61161a565b005b348015610732575f80fd5b5061074d600480360381019061074891906137c4565b611633565b005b34801561075a575f80fd5b50610763611695565b6040516107709190613172565b60405180910390f35b348015610784575f80fd5b5061078d6116a8565b60405161079a9190613215565b60405180910390f35b3480156107ae575f80fd5b506107b76116e1565b6040516107c49190613172565b60405180910390f35b3480156107d8575f80fd5b506107f360048036038101906107ee9190613268565b6116f3565b6040516108009190613215565b60405180910390f35b348015610814575f80fd5b5061082f600480360381019061082a91906133ef565b611764565b60405161083c91906133d6565b60405180910390f35b348015610850575f80fd5b5061086b60048036038101906108669190613844565b61187c565b6040516108789190613172565b60405180910390f35b34801561088c575f80fd5b506108a760048036038101906108a291906133ef565b61190a565b6040516108b491906133d6565b60405180910390f35b3480156108c8575f80fd5b506108e360048036038101906108de91906133ef565b61191f565b6040516108f091906133d6565b60405180910390f35b610913600480360381019061090e91906133ef565b611934565b005b61092f600480360381019061092a91906133ef565b611972565b005b34801561093c575f80fd5b50610957600480360381019061095291906133ef565b61199b565b60405161096491906133d6565b60405180910390f35b5f610977826119b4565b9050919050565b60605f805461098c906138af565b80601f01602080910402602001604051908101604052809291908181526020018280546109b8906138af565b8015610a035780601f106109da57610100808354040283529160200191610a03565b820191905f5260205f20905b8154815290600101906020018083116109e657829003601f168201915b5050505050905090565b5f610a1782611a14565b60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b81610a7e81611a5f565b610a888383611b59565b505050565b600d5481565b610a9b611c6f565b80600e5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f600880549050905090565b823373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b2857610b2733611a5f565b5b610b33848484611c8b565b50505050565b5f610b42611ceb565b67ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b5f610b948361132a565b8210610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bcc9061394f565b60405180910390fd5b60065f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f2054905092915050565b73565abc3feaa3bc3820b83620f4bbf16b5c4d47a381565b600b5f9054906101000a900460ff16610c87576040517f80cb55e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34600d5483839050610c99919061399a565b14610cd0576040517f313223b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b82829050811015610e16573373ffffffffffffffffffffffffffffffffffffffff1673565abc3feaa3bc3820b83620f4bbf16b5c4d47a373ffffffffffffffffffffffffffffffffffffffff16636352211e858585818110610d3757610d366139db565b5b905060200201356040518263ffffffff1660e01b8152600401610d5a91906133d6565b602060405180830381865afa158015610d75573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d999190613a1c565b73ffffffffffffffffffffffffffffffffffffffff1614610de6576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e0933848484818110610dfd57610dfc6139db565b5b90506020020135611cf5565b8080600101915050610cd2565b505050565b610e23611c6f565b600b5f9054906101000a900460ff1615600b5f6101000a81548160ff021916908315150217905550565b6daaeb6d7670e522a718067333cd4e81565b823373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610e9d57610e9c33611a5f565b5b610ea8848484611d12565b50505050565b5f610eb7610ade565b8210610ef8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eef90613ab7565b60405180910390fd5b60088281548110610f0c57610f0b6139db565b5b905f5260205f2001549050919050565b610f24611c6f565b80600d8190555050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b610f6f611c6f565b80600c9081610f7e9190613c69565b5050565b600b60019054906101000a900460ff16610fc8576040517f24fbaa9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610fd9610fd4611d31565b61132a565b90505f8103611014576040517fbe7538fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8060105f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f4290505f82146110d6578062015180836110719190613d38565b11156110a9576040517f748614c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60056201518083836110bb9190613d6b565b6110c59190613dcb565b6110cf919061399a565b925061111f565b6005620151807f0000000000000000000000000000000000000000000000000000000000000000836111089190613d6b565b6111129190613dcb565b61111c919061399a565b92505b8060105f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055505f848461116e919061399a565b905080600f5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282540192505081905550600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33670de0b6b3a76400008461120c919061399a565b6040518363ffffffff1660e01b8152600401611229929190613dfb565b6020604051808303815f875af1158015611245573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112699190613e36565b61129f576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b5f806112b183611d38565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611321576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161131890613eab565b60405180910390fd5b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611399576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161139090613f39565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6113e6611c6f565b6113ef5f611d71565b565b6113f9611c6f565b600b60019054906101000a900460ff1615600b60016101000a81548160ff021916908315150217905550565b61142d611c6f565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff1660e01b8152600401611489929190613dfb565b6020604051808303815f875af11580156114a5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c99190613e36565b5050565b5f638b78c6d81954905090565b6060600180546114e9906138af565b80601f0160208091040260200160405190810160405280929190818152602001828054611515906138af565b80156115605780601f1061153757610100808354040283529160200191611560565b820191905f5260205f20905b81548152906001019060200180831161154357829003601f168201915b5050505050905090565b600c8054611577906138af565b80601f01602080910402602001604051908101604052809291908181526020018280546115a3906138af565b80156115ee5780601f106115c5576101008083540402835291602001916115ee565b820191905f5260205f20905b8154815290600101906020018083116115d157829003601f168201915b505050505081565b7f000000000000000000000000000000000000000000000000000000000000000081565b8161162481611a5f565b61162e8383611dae565b505050565b61164461163e611d31565b83611dc4565b611683576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167a90613fc7565b60405180910390fd5b61168f84848484611e58565b50505050565b600b60019054906101000a900460ff1681565b6040518060400160405280600581526020017f2e6a736f6e00000000000000000000000000000000000000000000000000000081525081565b600b5f9054906101000a900460ff1681565b60606116fd611eb4565b61170683611f44565b6040518060400160405280600581526020017f2e6a736f6e00000000000000000000000000000000000000000000000000000081525060405160200161174e9392919061401f565b6040516020818303038152906040529050919050565b5f80611776611771611d31565b61132a565b90505f4290505f820361178d575f92505050611877565b5f8060105f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f81146118035760056201518082856117e89190613d6b565b6117f29190613dcb565b6117fc919061399a565b915061184c565b6005620151807f0000000000000000000000000000000000000000000000000000000000000000856118359190613d6b565b61183f9190613dcb565b611849919061399a565b91505b5f8483611859919061399a565b9050670de0b6b3a76400008161186f919061399a565b955050505050505b919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b6010602052805f5260405f205f915090505481565b600f602052805f5260405f205f915090505481565b61193c611c6f565b63389a75e1600c52805f526020600c20805442111561196257636f5e88185f526004601cfd5b5f81555061196f81611d71565b50565b61197a611c6f565b8060601b61198f57637448fbae5f526004601cfd5b61199881611d71565b50565b5f63389a75e1600c52815f526020600c20549050919050565b5f634906490660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611a0d5750611a0c8261200e565b5b9050919050565b611a1d81612087565b611a5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a5390613eab565b60405180910390fd5b50565b5f6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115611b56576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401611ad592919061404f565b602060405180830381865afa158015611af0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b149190613e36565b611b5557806040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401611b4c91906132d2565b60405180910390fd5b5b50565b5f611b63826112a6565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611bd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bca906140e6565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16611bf2611d31565b73ffffffffffffffffffffffffffffffffffffffff161480611c215750611c2081611c1b611d31565b61187c565b5b611c60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c5790614174565b60405180910390fd5b611c6a83836120c7565b505050565b638b78c6d819543314611c89576382b429005f526004601cfd5b565b611c9c611c96611d31565b82611dc4565b611cdb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd290613fc7565b60405180910390fd5b611ce683838361217d565b505050565b5f6202a300905090565b611d0e828260405180602001604052805f815250612469565b5050565b611d2c83838360405180602001604052805f815250611633565b505050565b5f33905090565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b638b78c6d8198160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a38181555050565b611dc0611db9611d31565b83836124c3565b5050565b5f80611dcf836112a6565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480611e115750611e10818561187c565b5b80611e4f57508373ffffffffffffffffffffffffffffffffffffffff16611e3784610a0d565b73ffffffffffffffffffffffffffffffffffffffff16145b91505092915050565b611e6384848461217d565b611e6f8484848461262a565b611eae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ea590614202565b60405180910390fd5b50505050565b6060600c8054611ec3906138af565b80601f0160208091040260200160405190810160405280929190818152602001828054611eef906138af565b8015611f3a5780601f10611f1157610100808354040283529160200191611f3a565b820191905f5260205f20905b815481529060010190602001808311611f1d57829003601f168201915b5050505050905090565b60605f6001611f52846127ac565b0190505f8167ffffffffffffffff811115611f7057611f6f613553565b5b6040519080825280601f01601f191660200182016040528015611fa25781602001600182028036833780820191505090505b5090505f82602001820190505b600115612003578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611ff857611ff7613d9e565b5b0494505f8503611faf575b819350505050919050565b5f7f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612080575061207f826128fd565b5b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff166120a883611d38565b73ffffffffffffffffffffffffffffffffffffffff1614159050919050565b8160045f8381526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16612137836112a6565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b8273ffffffffffffffffffffffffffffffffffffffff1661219d826112a6565b73ffffffffffffffffffffffffffffffffffffffff16146121f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121ea90614290565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612261576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122589061431e565b60405180910390fd5b61226e83838360016129de565b8273ffffffffffffffffffffffffffffffffffffffff1661228e826112a6565b73ffffffffffffffffffffffffffffffffffffffff16146122e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122db90614290565b60405180910390fd5b60045f8281526020019081526020015f205f6101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600160035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282540392505081905550600160035f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508160025f8381526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a461246483838360016129f0565b505050565b61247383836129f6565b61247f5f84848461262a565b6124be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124b590614202565b60405180910390fd5b505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612531576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252890614386565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405161261d9190613172565b60405180910390a3505050565b5f61264a8473ffffffffffffffffffffffffffffffffffffffff16612c09565b1561279f578373ffffffffffffffffffffffffffffffffffffffff1663150b7a02612673611d31565b8786866040518563ffffffff1660e01b815260040161269594939291906143f6565b6020604051808303815f875af19250505080156126d057506040513d601f19601f820116820180604052508101906126cd9190614454565b60015b61274f573d805f81146126fe576040519150601f19603f3d011682016040523d82523d5f602084013e612703565b606091505b505f815103612747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161273e90614202565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150506127a4565b600190505b949350505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612808577a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083816127fe576127fd613d9e565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612845576d04ee2d6d415b85acef8100000000838161283b5761283a613d9e565b5b0492506020810190505b662386f26fc10000831061287457662386f26fc10000838161286a57612869613d9e565b5b0492506010810190505b6305f5e100831061289d576305f5e100838161289357612892613d9e565b5b0492506008810190505b61271083106128c25761271083816128b8576128b7613d9e565b5b0492506004810190505b606483106128e557606483816128db576128da613d9e565b5b0492506002810190505b600a83106128f4576001810190505b80915050919050565b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806129c757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806129d757506129d682612c2b565b5b9050919050565b6129ea84848484612c94565b50505050565b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612a64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a5b906144c9565b60405180910390fd5b612a6d81612087565b15612aad576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612aa490614531565b60405180910390fd5b612aba5f838360016129de565b612ac381612087565b15612b03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612afa90614531565b60405180910390fd5b600160035f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508160025f8381526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4612c055f838360016129f0565b5050565b5f808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b612ca084848484612def565b6001811115612ce4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cdb906145bf565b60405180910390fd5b5f8290505f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612d2957612d2481612df5565b612d68565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614612d6757612d668582612e39565b5b5b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612da957612da481612f8f565b612de8565b8473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614612de757612de6848261304f565b5b5b5050505050565b50505050565b60088054905060095f8381526020019081526020015f2081905550600881908060018154018082558091505060019003905f5260205f20015f909190919091505550565b5f6001612e458461132a565b612e4f9190613d6b565b90505f60075f8481526020019081526020015f20549050818114612f26575f60065f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f205490508060065f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f20819055508160075f8381526020019081526020015f2081905550505b60075f8481526020019081526020015f205f905560065f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f205f905550505050565b5f6001600880549050612fa29190613d6b565b90505f60095f8481526020019081526020015f205490505f60088381548110612fce57612fcd6139db565b5b905f5260205f20015490508060088381548110612fee57612fed6139db565b5b905f5260205f2001819055508160095f8381526020019081526020015f208190555060095f8581526020019081526020015f205f90556008805480613036576130356145dd565b5b600190038181905f5260205f20015f9055905550505050565b5f6130598361132a565b90508160065f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f20819055508060075f8481526020019081526020015f2081905550505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61310c816130d8565b8114613116575f80fd5b50565b5f8135905061312781613103565b92915050565b5f60208284031215613142576131416130d0565b5b5f61314f84828501613119565b91505092915050565b5f8115159050919050565b61316c81613158565b82525050565b5f6020820190506131855f830184613163565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156131c25780820151818401526020810190506131a7565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6131e78261318b565b6131f18185613195565b93506132018185602086016131a5565b61320a816131cd565b840191505092915050565b5f6020820190508181035f83015261322d81846131dd565b905092915050565b5f819050919050565b61324781613235565b8114613251575f80fd5b50565b5f813590506132628161323e565b92915050565b5f6020828403121561327d5761327c6130d0565b5b5f61328a84828501613254565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6132bc82613293565b9050919050565b6132cc816132b2565b82525050565b5f6020820190506132e55f8301846132c3565b92915050565b5f819050919050565b5f61330e61330961330484613293565b6132eb565b613293565b9050919050565b5f61331f826132f4565b9050919050565b5f61333082613315565b9050919050565b61334081613326565b82525050565b5f6020820190506133595f830184613337565b92915050565b613368816132b2565b8114613372575f80fd5b50565b5f813590506133838161335f565b92915050565b5f806040838503121561339f5761339e6130d0565b5b5f6133ac85828601613375565b92505060206133bd85828601613254565b9150509250929050565b6133d081613235565b82525050565b5f6020820190506133e95f8301846133c7565b92915050565b5f60208284031215613404576134036130d0565b5b5f61341184828501613375565b91505092915050565b5f805f60608486031215613431576134306130d0565b5b5f61343e86828701613375565b935050602061344f86828701613375565b925050604061346086828701613254565b9150509250925092565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261348b5761348a61346a565b5b8235905067ffffffffffffffff8111156134a8576134a761346e565b5b6020830191508360208202830111156134c4576134c3613472565b5b9250929050565b5f80602083850312156134e1576134e06130d0565b5b5f83013567ffffffffffffffff8111156134fe576134fd6130d4565b5b61350a85828601613476565b92509250509250929050565b5f61352082613315565b9050919050565b61353081613516565b82525050565b5f6020820190506135495f830184613527565b92915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b613589826131cd565b810181811067ffffffffffffffff821117156135a8576135a7613553565b5b80604052505050565b5f6135ba6130c7565b90506135c68282613580565b919050565b5f67ffffffffffffffff8211156135e5576135e4613553565b5b6135ee826131cd565b9050602081019050919050565b828183375f83830152505050565b5f61361b613616846135cb565b6135b1565b9050828152602081018484840111156136375761363661354f565b5b6136428482856135fb565b509392505050565b5f82601f83011261365e5761365d61346a565b5b813561366e848260208601613609565b91505092915050565b5f6020828403121561368c5761368b6130d0565b5b5f82013567ffffffffffffffff8111156136a9576136a86130d4565b5b6136b58482850161364a565b91505092915050565b6136c781613158565b81146136d1575f80fd5b50565b5f813590506136e2816136be565b92915050565b5f80604083850312156136fe576136fd6130d0565b5b5f61370b85828601613375565b925050602061371c858286016136d4565b9150509250929050565b5f67ffffffffffffffff8211156137405761373f613553565b5b613749826131cd565b9050602081019050919050565b5f61376861376384613726565b6135b1565b9050828152602081018484840111156137845761378361354f565b5b61378f8482856135fb565b509392505050565b5f82601f8301126137ab576137aa61346a565b5b81356137bb848260208601613756565b91505092915050565b5f805f80608085870312156137dc576137db6130d0565b5b5f6137e987828801613375565b94505060206137fa87828801613375565b935050604061380b87828801613254565b925050606085013567ffffffffffffffff81111561382c5761382b6130d4565b5b61383887828801613797565b91505092959194509250565b5f806040838503121561385a576138596130d0565b5b5f61386785828601613375565b925050602061387885828601613375565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806138c657607f821691505b6020821081036138d9576138d8613882565b5b50919050565b7f455243373231456e756d657261626c653a206f776e657220696e646578206f755f8201527f74206f6620626f756e6473000000000000000000000000000000000000000000602082015250565b5f613939602b83613195565b9150613944826138df565b604082019050919050565b5f6020820190508181035f8301526139668161392d565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6139a482613235565b91506139af83613235565b92508282026139bd81613235565b915082820484148315176139d4576139d361396d565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f81519050613a168161335f565b92915050565b5f60208284031215613a3157613a306130d0565b5b5f613a3e84828501613a08565b91505092915050565b7f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f5f8201527f7574206f6620626f756e64730000000000000000000000000000000000000000602082015250565b5f613aa1602c83613195565b9150613aac82613a47565b604082019050919050565b5f6020820190508181035f830152613ace81613a95565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302613b317fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82613af6565b613b3b8683613af6565b95508019841693508086168417925050509392505050565b5f613b6d613b68613b6384613235565b6132eb565b613235565b9050919050565b5f819050919050565b613b8683613b53565b613b9a613b9282613b74565b848454613b02565b825550505050565b5f90565b613bae613ba2565b613bb9818484613b7d565b505050565b5b81811015613bdc57613bd15f82613ba6565b600181019050613bbf565b5050565b601f821115613c2157613bf281613ad5565b613bfb84613ae7565b81016020851015613c0a578190505b613c1e613c1685613ae7565b830182613bbe565b50505b505050565b5f82821c905092915050565b5f613c415f1984600802613c26565b1980831691505092915050565b5f613c598383613c32565b9150826002028217905092915050565b613c728261318b565b67ffffffffffffffff811115613c8b57613c8a613553565b5b613c9582546138af565b613ca0828285613be0565b5f60209050601f831160018114613cd1575f8415613cbf578287015190505b613cc98582613c4e565b865550613d30565b601f198416613cdf86613ad5565b5f5b82811015613d0657848901518255600182019150602085019450602081019050613ce1565b86831015613d235784890151613d1f601f891682613c32565b8355505b6001600288020188555050505b505050505050565b5f613d4282613235565b9150613d4d83613235565b9250828201905080821115613d6557613d6461396d565b5b92915050565b5f613d7582613235565b9150613d8083613235565b9250828203905081811115613d9857613d9761396d565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613dd582613235565b9150613de083613235565b925082613df057613def613d9e565b5b828204905092915050565b5f604082019050613e0e5f8301856132c3565b613e1b60208301846133c7565b9392505050565b5f81519050613e30816136be565b92915050565b5f60208284031215613e4b57613e4a6130d0565b5b5f613e5884828501613e22565b91505092915050565b7f4552433732313a20696e76616c696420746f6b656e20494400000000000000005f82015250565b5f613e95601883613195565b9150613ea082613e61565b602082019050919050565b5f6020820190508181035f830152613ec281613e89565b9050919050565b7f4552433732313a2061646472657373207a65726f206973206e6f7420612076615f8201527f6c6964206f776e65720000000000000000000000000000000000000000000000602082015250565b5f613f23602983613195565b9150613f2e82613ec9565b604082019050919050565b5f6020820190508181035f830152613f5081613f17565b9050919050565b7f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e655f8201527f72206f7220617070726f76656400000000000000000000000000000000000000602082015250565b5f613fb1602d83613195565b9150613fbc82613f57565b604082019050919050565b5f6020820190508181035f830152613fde81613fa5565b9050919050565b5f81905092915050565b5f613ff98261318b565b6140038185613fe5565b93506140138185602086016131a5565b80840191505092915050565b5f61402a8286613fef565b91506140368285613fef565b91506140428284613fef565b9150819050949350505050565b5f6040820190506140625f8301856132c3565b61406f60208301846132c3565b9392505050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e655f8201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b5f6140d0602183613195565b91506140db82614076565b604082019050919050565b5f6020820190508181035f8301526140fd816140c4565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f5f8201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000602082015250565b5f61415e603d83613195565b915061416982614104565b604082019050919050565b5f6020820190508181035f83015261418b81614152565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e2045524337323152655f8201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b5f6141ec603283613195565b91506141f782614192565b604082019050919050565b5f6020820190508181035f830152614219816141e0565b9050919050565b7f4552433732313a207472616e736665722066726f6d20696e636f7272656374205f8201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b5f61427a602583613195565b915061428582614220565b604082019050919050565b5f6020820190508181035f8301526142a78161426e565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f614308602483613195565b9150614313826142ae565b604082019050919050565b5f6020820190508181035f830152614335816142fc565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c6572000000000000005f82015250565b5f614370601983613195565b915061437b8261433c565b602082019050919050565b5f6020820190508181035f83015261439d81614364565b9050919050565b5f81519050919050565b5f82825260208201905092915050565b5f6143c8826143a4565b6143d281856143ae565b93506143e28185602086016131a5565b6143eb816131cd565b840191505092915050565b5f6080820190506144095f8301876132c3565b61441660208301866132c3565b61442360408301856133c7565b818103606083015261443581846143be565b905095945050505050565b5f8151905061444e81613103565b92915050565b5f60208284031215614469576144686130d0565b5b5f61447684828501614440565b91505092915050565b7f4552433732313a206d696e7420746f20746865207a65726f20616464726573735f82015250565b5f6144b3602083613195565b91506144be8261447f565b602082019050919050565b5f6020820190508181035f8301526144e0816144a7565b9050919050565b7f4552433732313a20746f6b656e20616c7265616479206d696e746564000000005f82015250565b5f61451b601c83613195565b9150614526826144e7565b602082019050919050565b5f6020820190508181035f8301526145488161450f565b9050919050565b7f455243373231456e756d657261626c653a20636f6e73656375746976652074725f8201527f616e7366657273206e6f7420737570706f727465640000000000000000000000602082015250565b5f6145a9603583613195565b91506145b48261454f565b604082019050919050565b5f6020820190508181035f8301526145d68161459d565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea2646970667358221220b33bbdf69fe3fc3dffa8908864c177301ae8d1fb98204f8b3567fee043a3db2764736f6c63430008150033697066733a2f2f516d594a47456f61337a524e4d56464c735263677a584e4e5133673248735151656970534c4673746976573468422f

Deployed Bytecode

0x60806040526004361061025b575f3560e01c80636352211e11610143578063c60360f7116100b5578063e985e9c511610079578063e985e9c514610845578063eca30a4114610881578063ef5d9ae8146108bd578063f04e283e146108f9578063f2fde38b14610915578063fee81cf4146109315761025b565b8063c60360f71461074f578063c668286214610779578063c67c74d4146107a3578063c87b56dd146107cd578063e5267d17146108095761025b565b80638da5cb5b116101075780638da5cb5b1461065757806395d89b41146106815780639abc8320146106ab5780639ced0e9b146106d5578063a22cb465146106ff578063b88d4fde146107275761025b565b80636352211e1461059757806370a08231146105d3578063715018a61461060f5780637e082c16146106195780638c1ceda51461062f5761025b565b80632f745c59116101dc57806342842e0e116101a057806342842e0e146104c35780634f6ccce7146104eb57806351f468c01461052757806354d1f13d1461054f57806355f804b3146105595780635e08dff6146105815761025b565b80632f745c59146104015780633745ee951461043d578063381b1e5d14610467578063398280eb1461048357806341f43434146104995761025b565b806315d655c91161022357806315d655c91461035357806317d819d01461037d57806318160ddd146103a557806323b872dd146103cf57806325692962146103f75761025b565b806301ffc9a71461025f57806306fdde031461029b578063081812fc146102c557806308e0415814610301578063095ea7b31461032b575b5f80fd5b34801561026a575f80fd5b506102856004803603810190610280919061312d565b61096d565b6040516102929190613172565b60405180910390f35b3480156102a6575f80fd5b506102af61097e565b6040516102bc9190613215565b60405180910390f35b3480156102d0575f80fd5b506102eb60048036038101906102e69190613268565b610a0d565b6040516102f891906132d2565b60405180910390f35b34801561030c575f80fd5b50610315610a4f565b6040516103229190613346565b60405180910390f35b348015610336575f80fd5b50610351600480360381019061034c9190613389565b610a74565b005b34801561035e575f80fd5b50610367610a8d565b60405161037491906133d6565b60405180910390f35b348015610388575f80fd5b506103a3600480360381019061039e91906133ef565b610a93565b005b3480156103b0575f80fd5b506103b9610ade565b6040516103c691906133d6565b60405180910390f35b3480156103da575f80fd5b506103f560048036038101906103f0919061341a565b610aea565b005b6103ff610b39565b005b34801561040c575f80fd5b5061042760048036038101906104229190613389565b610b8a565b60405161043491906133d6565b60405180910390f35b348015610448575f80fd5b50610451610c2a565b60405161045e91906132d2565b60405180910390f35b610481600480360381019061047c91906134cb565b610c42565b005b34801561048e575f80fd5b50610497610e1b565b005b3480156104a4575f80fd5b506104ad610e4d565b6040516104ba9190613536565b60405180910390f35b3480156104ce575f80fd5b506104e960048036038101906104e4919061341a565b610e5f565b005b3480156104f6575f80fd5b50610511600480360381019061050c9190613268565b610eae565b60405161051e91906133d6565b60405180910390f35b348015610532575f80fd5b5061054d60048036038101906105489190613268565b610f1c565b005b610557610f2e565b005b348015610564575f80fd5b5061057f600480360381019061057a9190613677565b610f67565b005b34801561058c575f80fd5b50610595610f82565b005b3480156105a2575f80fd5b506105bd60048036038101906105b89190613268565b6112a6565b6040516105ca91906132d2565b60405180910390f35b3480156105de575f80fd5b506105f960048036038101906105f491906133ef565b61132a565b60405161060691906133d6565b60405180910390f35b6106176113de565b005b348015610624575f80fd5b5061062d6113f1565b005b34801561063a575f80fd5b5061065560048036038101906106509190613268565b611425565b005b348015610662575f80fd5b5061066b6114cd565b60405161067891906132d2565b60405180910390f35b34801561068c575f80fd5b506106956114da565b6040516106a29190613215565b60405180910390f35b3480156106b6575f80fd5b506106bf61156a565b6040516106cc9190613215565b60405180910390f35b3480156106e0575f80fd5b506106e96115f6565b6040516106f691906133d6565b60405180910390f35b34801561070a575f80fd5b50610725600480360381019061072091906136e8565b61161a565b005b348015610732575f80fd5b5061074d600480360381019061074891906137c4565b611633565b005b34801561075a575f80fd5b50610763611695565b6040516107709190613172565b60405180910390f35b348015610784575f80fd5b5061078d6116a8565b60405161079a9190613215565b60405180910390f35b3480156107ae575f80fd5b506107b76116e1565b6040516107c49190613172565b60405180910390f35b3480156107d8575f80fd5b506107f360048036038101906107ee9190613268565b6116f3565b6040516108009190613215565b60405180910390f35b348015610814575f80fd5b5061082f600480360381019061082a91906133ef565b611764565b60405161083c91906133d6565b60405180910390f35b348015610850575f80fd5b5061086b60048036038101906108669190613844565b61187c565b6040516108789190613172565b60405180910390f35b34801561088c575f80fd5b506108a760048036038101906108a291906133ef565b61190a565b6040516108b491906133d6565b60405180910390f35b3480156108c8575f80fd5b506108e360048036038101906108de91906133ef565b61191f565b6040516108f091906133d6565b60405180910390f35b610913600480360381019061090e91906133ef565b611934565b005b61092f600480360381019061092a91906133ef565b611972565b005b34801561093c575f80fd5b50610957600480360381019061095291906133ef565b61199b565b60405161096491906133d6565b60405180910390f35b5f610977826119b4565b9050919050565b60605f805461098c906138af565b80601f01602080910402602001604051908101604052809291908181526020018280546109b8906138af565b8015610a035780601f106109da57610100808354040283529160200191610a03565b820191905f5260205f20905b8154815290600101906020018083116109e657829003601f168201915b5050505050905090565b5f610a1782611a14565b60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b81610a7e81611a5f565b610a888383611b59565b505050565b600d5481565b610a9b611c6f565b80600e5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f600880549050905090565b823373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b2857610b2733611a5f565b5b610b33848484611c8b565b50505050565b5f610b42611ceb565b67ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b5f610b948361132a565b8210610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bcc9061394f565b60405180910390fd5b60065f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f2054905092915050565b73565abc3feaa3bc3820b83620f4bbf16b5c4d47a381565b600b5f9054906101000a900460ff16610c87576040517f80cb55e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34600d5483839050610c99919061399a565b14610cd0576040517f313223b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b82829050811015610e16573373ffffffffffffffffffffffffffffffffffffffff1673565abc3feaa3bc3820b83620f4bbf16b5c4d47a373ffffffffffffffffffffffffffffffffffffffff16636352211e858585818110610d3757610d366139db565b5b905060200201356040518263ffffffff1660e01b8152600401610d5a91906133d6565b602060405180830381865afa158015610d75573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d999190613a1c565b73ffffffffffffffffffffffffffffffffffffffff1614610de6576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e0933848484818110610dfd57610dfc6139db565b5b90506020020135611cf5565b8080600101915050610cd2565b505050565b610e23611c6f565b600b5f9054906101000a900460ff1615600b5f6101000a81548160ff021916908315150217905550565b6daaeb6d7670e522a718067333cd4e81565b823373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610e9d57610e9c33611a5f565b5b610ea8848484611d12565b50505050565b5f610eb7610ade565b8210610ef8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eef90613ab7565b60405180910390fd5b60088281548110610f0c57610f0b6139db565b5b905f5260205f2001549050919050565b610f24611c6f565b80600d8190555050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b610f6f611c6f565b80600c9081610f7e9190613c69565b5050565b600b60019054906101000a900460ff16610fc8576040517f24fbaa9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610fd9610fd4611d31565b61132a565b90505f8103611014576040517fbe7538fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8060105f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f4290505f82146110d6578062015180836110719190613d38565b11156110a9576040517f748614c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60056201518083836110bb9190613d6b565b6110c59190613dcb565b6110cf919061399a565b925061111f565b6005620151807f0000000000000000000000000000000000000000000000000000000064f1133b836111089190613d6b565b6111129190613dcb565b61111c919061399a565b92505b8060105f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055505f848461116e919061399a565b905080600f5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282540192505081905550600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33670de0b6b3a76400008461120c919061399a565b6040518363ffffffff1660e01b8152600401611229929190613dfb565b6020604051808303815f875af1158015611245573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112699190613e36565b61129f576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b5f806112b183611d38565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611321576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161131890613eab565b60405180910390fd5b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611399576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161139090613f39565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6113e6611c6f565b6113ef5f611d71565b565b6113f9611c6f565b600b60019054906101000a900460ff1615600b60016101000a81548160ff021916908315150217905550565b61142d611c6f565b600e5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff1660e01b8152600401611489929190613dfb565b6020604051808303815f875af11580156114a5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c99190613e36565b5050565b5f638b78c6d81954905090565b6060600180546114e9906138af565b80601f0160208091040260200160405190810160405280929190818152602001828054611515906138af565b80156115605780601f1061153757610100808354040283529160200191611560565b820191905f5260205f20905b81548152906001019060200180831161154357829003601f168201915b5050505050905090565b600c8054611577906138af565b80601f01602080910402602001604051908101604052809291908181526020018280546115a3906138af565b80156115ee5780601f106115c5576101008083540402835291602001916115ee565b820191905f5260205f20905b8154815290600101906020018083116115d157829003601f168201915b505050505081565b7f0000000000000000000000000000000000000000000000000000000064f1133b81565b8161162481611a5f565b61162e8383611dae565b505050565b61164461163e611d31565b83611dc4565b611683576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167a90613fc7565b60405180910390fd5b61168f84848484611e58565b50505050565b600b60019054906101000a900460ff1681565b6040518060400160405280600581526020017f2e6a736f6e00000000000000000000000000000000000000000000000000000081525081565b600b5f9054906101000a900460ff1681565b60606116fd611eb4565b61170683611f44565b6040518060400160405280600581526020017f2e6a736f6e00000000000000000000000000000000000000000000000000000081525060405160200161174e9392919061401f565b6040516020818303038152906040529050919050565b5f80611776611771611d31565b61132a565b90505f4290505f820361178d575f92505050611877565b5f8060105f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f81146118035760056201518082856117e89190613d6b565b6117f29190613dcb565b6117fc919061399a565b915061184c565b6005620151807f0000000000000000000000000000000000000000000000000000000064f1133b856118359190613d6b565b61183f9190613dcb565b611849919061399a565b91505b5f8483611859919061399a565b9050670de0b6b3a76400008161186f919061399a565b955050505050505b919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b6010602052805f5260405f205f915090505481565b600f602052805f5260405f205f915090505481565b61193c611c6f565b63389a75e1600c52805f526020600c20805442111561196257636f5e88185f526004601cfd5b5f81555061196f81611d71565b50565b61197a611c6f565b8060601b61198f57637448fbae5f526004601cfd5b61199881611d71565b50565b5f63389a75e1600c52815f526020600c20549050919050565b5f634906490660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611a0d5750611a0c8261200e565b5b9050919050565b611a1d81612087565b611a5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a5390613eab565b60405180910390fd5b50565b5f6daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff163b1115611b56576daaeb6d7670e522a718067333cd4e73ffffffffffffffffffffffffffffffffffffffff1663c617113430836040518363ffffffff1660e01b8152600401611ad592919061404f565b602060405180830381865afa158015611af0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b149190613e36565b611b5557806040517fede71dcc000000000000000000000000000000000000000000000000000000008152600401611b4c91906132d2565b60405180910390fd5b5b50565b5f611b63826112a6565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611bd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bca906140e6565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16611bf2611d31565b73ffffffffffffffffffffffffffffffffffffffff161480611c215750611c2081611c1b611d31565b61187c565b5b611c60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c5790614174565b60405180910390fd5b611c6a83836120c7565b505050565b638b78c6d819543314611c89576382b429005f526004601cfd5b565b611c9c611c96611d31565b82611dc4565b611cdb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd290613fc7565b60405180910390fd5b611ce683838361217d565b505050565b5f6202a300905090565b611d0e828260405180602001604052805f815250612469565b5050565b611d2c83838360405180602001604052805f815250611633565b505050565b5f33905090565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b638b78c6d8198160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a38181555050565b611dc0611db9611d31565b83836124c3565b5050565b5f80611dcf836112a6565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480611e115750611e10818561187c565b5b80611e4f57508373ffffffffffffffffffffffffffffffffffffffff16611e3784610a0d565b73ffffffffffffffffffffffffffffffffffffffff16145b91505092915050565b611e6384848461217d565b611e6f8484848461262a565b611eae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ea590614202565b60405180910390fd5b50505050565b6060600c8054611ec3906138af565b80601f0160208091040260200160405190810160405280929190818152602001828054611eef906138af565b8015611f3a5780601f10611f1157610100808354040283529160200191611f3a565b820191905f5260205f20905b815481529060010190602001808311611f1d57829003601f168201915b5050505050905090565b60605f6001611f52846127ac565b0190505f8167ffffffffffffffff811115611f7057611f6f613553565b5b6040519080825280601f01601f191660200182016040528015611fa25781602001600182028036833780820191505090505b5090505f82602001820190505b600115612003578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611ff857611ff7613d9e565b5b0494505f8503611faf575b819350505050919050565b5f7f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612080575061207f826128fd565b5b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff166120a883611d38565b73ffffffffffffffffffffffffffffffffffffffff1614159050919050565b8160045f8381526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16612137836112a6565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b8273ffffffffffffffffffffffffffffffffffffffff1661219d826112a6565b73ffffffffffffffffffffffffffffffffffffffff16146121f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121ea90614290565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612261576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122589061431e565b60405180910390fd5b61226e83838360016129de565b8273ffffffffffffffffffffffffffffffffffffffff1661228e826112a6565b73ffffffffffffffffffffffffffffffffffffffff16146122e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122db90614290565b60405180910390fd5b60045f8281526020019081526020015f205f6101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600160035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282540392505081905550600160035f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508160025f8381526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a461246483838360016129f0565b505050565b61247383836129f6565b61247f5f84848461262a565b6124be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124b590614202565b60405180910390fd5b505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612531576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252890614386565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405161261d9190613172565b60405180910390a3505050565b5f61264a8473ffffffffffffffffffffffffffffffffffffffff16612c09565b1561279f578373ffffffffffffffffffffffffffffffffffffffff1663150b7a02612673611d31565b8786866040518563ffffffff1660e01b815260040161269594939291906143f6565b6020604051808303815f875af19250505080156126d057506040513d601f19601f820116820180604052508101906126cd9190614454565b60015b61274f573d805f81146126fe576040519150601f19603f3d011682016040523d82523d5f602084013e612703565b606091505b505f815103612747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161273e90614202565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150506127a4565b600190505b949350505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612808577a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083816127fe576127fd613d9e565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612845576d04ee2d6d415b85acef8100000000838161283b5761283a613d9e565b5b0492506020810190505b662386f26fc10000831061287457662386f26fc10000838161286a57612869613d9e565b5b0492506010810190505b6305f5e100831061289d576305f5e100838161289357612892613d9e565b5b0492506008810190505b61271083106128c25761271083816128b8576128b7613d9e565b5b0492506004810190505b606483106128e557606483816128db576128da613d9e565b5b0492506002810190505b600a83106128f4576001810190505b80915050919050565b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806129c757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806129d757506129d682612c2b565b5b9050919050565b6129ea84848484612c94565b50505050565b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612a64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a5b906144c9565b60405180910390fd5b612a6d81612087565b15612aad576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612aa490614531565b60405180910390fd5b612aba5f838360016129de565b612ac381612087565b15612b03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612afa90614531565b60405180910390fd5b600160035f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508160025f8381526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4612c055f838360016129f0565b5050565b5f808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b612ca084848484612def565b6001811115612ce4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cdb906145bf565b60405180910390fd5b5f8290505f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612d2957612d2481612df5565b612d68565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614612d6757612d668582612e39565b5b5b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612da957612da481612f8f565b612de8565b8473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614612de757612de6848261304f565b5b5b5050505050565b50505050565b60088054905060095f8381526020019081526020015f2081905550600881908060018154018082558091505060019003905f5260205f20015f909190919091505550565b5f6001612e458461132a565b612e4f9190613d6b565b90505f60075f8481526020019081526020015f20549050818114612f26575f60065f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f205490508060065f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f20819055508160075f8381526020019081526020015f2081905550505b60075f8481526020019081526020015f205f905560065f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f205f905550505050565b5f6001600880549050612fa29190613d6b565b90505f60095f8481526020019081526020015f205490505f60088381548110612fce57612fcd6139db565b5b905f5260205f20015490508060088381548110612fee57612fed6139db565b5b905f5260205f2001819055508160095f8381526020019081526020015f208190555060095f8581526020019081526020015f205f90556008805480613036576130356145dd565b5b600190038181905f5260205f20015f9055905550505050565b5f6130598361132a565b90508160065f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f20819055508060075f8481526020019081526020015f2081905550505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61310c816130d8565b8114613116575f80fd5b50565b5f8135905061312781613103565b92915050565b5f60208284031215613142576131416130d0565b5b5f61314f84828501613119565b91505092915050565b5f8115159050919050565b61316c81613158565b82525050565b5f6020820190506131855f830184613163565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156131c25780820151818401526020810190506131a7565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6131e78261318b565b6131f18185613195565b93506132018185602086016131a5565b61320a816131cd565b840191505092915050565b5f6020820190508181035f83015261322d81846131dd565b905092915050565b5f819050919050565b61324781613235565b8114613251575f80fd5b50565b5f813590506132628161323e565b92915050565b5f6020828403121561327d5761327c6130d0565b5b5f61328a84828501613254565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6132bc82613293565b9050919050565b6132cc816132b2565b82525050565b5f6020820190506132e55f8301846132c3565b92915050565b5f819050919050565b5f61330e61330961330484613293565b6132eb565b613293565b9050919050565b5f61331f826132f4565b9050919050565b5f61333082613315565b9050919050565b61334081613326565b82525050565b5f6020820190506133595f830184613337565b92915050565b613368816132b2565b8114613372575f80fd5b50565b5f813590506133838161335f565b92915050565b5f806040838503121561339f5761339e6130d0565b5b5f6133ac85828601613375565b92505060206133bd85828601613254565b9150509250929050565b6133d081613235565b82525050565b5f6020820190506133e95f8301846133c7565b92915050565b5f60208284031215613404576134036130d0565b5b5f61341184828501613375565b91505092915050565b5f805f60608486031215613431576134306130d0565b5b5f61343e86828701613375565b935050602061344f86828701613375565b925050604061346086828701613254565b9150509250925092565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261348b5761348a61346a565b5b8235905067ffffffffffffffff8111156134a8576134a761346e565b5b6020830191508360208202830111156134c4576134c3613472565b5b9250929050565b5f80602083850312156134e1576134e06130d0565b5b5f83013567ffffffffffffffff8111156134fe576134fd6130d4565b5b61350a85828601613476565b92509250509250929050565b5f61352082613315565b9050919050565b61353081613516565b82525050565b5f6020820190506135495f830184613527565b92915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b613589826131cd565b810181811067ffffffffffffffff821117156135a8576135a7613553565b5b80604052505050565b5f6135ba6130c7565b90506135c68282613580565b919050565b5f67ffffffffffffffff8211156135e5576135e4613553565b5b6135ee826131cd565b9050602081019050919050565b828183375f83830152505050565b5f61361b613616846135cb565b6135b1565b9050828152602081018484840111156136375761363661354f565b5b6136428482856135fb565b509392505050565b5f82601f83011261365e5761365d61346a565b5b813561366e848260208601613609565b91505092915050565b5f6020828403121561368c5761368b6130d0565b5b5f82013567ffffffffffffffff8111156136a9576136a86130d4565b5b6136b58482850161364a565b91505092915050565b6136c781613158565b81146136d1575f80fd5b50565b5f813590506136e2816136be565b92915050565b5f80604083850312156136fe576136fd6130d0565b5b5f61370b85828601613375565b925050602061371c858286016136d4565b9150509250929050565b5f67ffffffffffffffff8211156137405761373f613553565b5b613749826131cd565b9050602081019050919050565b5f61376861376384613726565b6135b1565b9050828152602081018484840111156137845761378361354f565b5b61378f8482856135fb565b509392505050565b5f82601f8301126137ab576137aa61346a565b5b81356137bb848260208601613756565b91505092915050565b5f805f80608085870312156137dc576137db6130d0565b5b5f6137e987828801613375565b94505060206137fa87828801613375565b935050604061380b87828801613254565b925050606085013567ffffffffffffffff81111561382c5761382b6130d4565b5b61383887828801613797565b91505092959194509250565b5f806040838503121561385a576138596130d0565b5b5f61386785828601613375565b925050602061387885828601613375565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806138c657607f821691505b6020821081036138d9576138d8613882565b5b50919050565b7f455243373231456e756d657261626c653a206f776e657220696e646578206f755f8201527f74206f6620626f756e6473000000000000000000000000000000000000000000602082015250565b5f613939602b83613195565b9150613944826138df565b604082019050919050565b5f6020820190508181035f8301526139668161392d565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6139a482613235565b91506139af83613235565b92508282026139bd81613235565b915082820484148315176139d4576139d361396d565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f81519050613a168161335f565b92915050565b5f60208284031215613a3157613a306130d0565b5b5f613a3e84828501613a08565b91505092915050565b7f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f5f8201527f7574206f6620626f756e64730000000000000000000000000000000000000000602082015250565b5f613aa1602c83613195565b9150613aac82613a47565b604082019050919050565b5f6020820190508181035f830152613ace81613a95565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302613b317fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82613af6565b613b3b8683613af6565b95508019841693508086168417925050509392505050565b5f613b6d613b68613b6384613235565b6132eb565b613235565b9050919050565b5f819050919050565b613b8683613b53565b613b9a613b9282613b74565b848454613b02565b825550505050565b5f90565b613bae613ba2565b613bb9818484613b7d565b505050565b5b81811015613bdc57613bd15f82613ba6565b600181019050613bbf565b5050565b601f821115613c2157613bf281613ad5565b613bfb84613ae7565b81016020851015613c0a578190505b613c1e613c1685613ae7565b830182613bbe565b50505b505050565b5f82821c905092915050565b5f613c415f1984600802613c26565b1980831691505092915050565b5f613c598383613c32565b9150826002028217905092915050565b613c728261318b565b67ffffffffffffffff811115613c8b57613c8a613553565b5b613c9582546138af565b613ca0828285613be0565b5f60209050601f831160018114613cd1575f8415613cbf578287015190505b613cc98582613c4e565b865550613d30565b601f198416613cdf86613ad5565b5f5b82811015613d0657848901518255600182019150602085019450602081019050613ce1565b86831015613d235784890151613d1f601f891682613c32565b8355505b6001600288020188555050505b505050505050565b5f613d4282613235565b9150613d4d83613235565b9250828201905080821115613d6557613d6461396d565b5b92915050565b5f613d7582613235565b9150613d8083613235565b9250828203905081811115613d9857613d9761396d565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613dd582613235565b9150613de083613235565b925082613df057613def613d9e565b5b828204905092915050565b5f604082019050613e0e5f8301856132c3565b613e1b60208301846133c7565b9392505050565b5f81519050613e30816136be565b92915050565b5f60208284031215613e4b57613e4a6130d0565b5b5f613e5884828501613e22565b91505092915050565b7f4552433732313a20696e76616c696420746f6b656e20494400000000000000005f82015250565b5f613e95601883613195565b9150613ea082613e61565b602082019050919050565b5f6020820190508181035f830152613ec281613e89565b9050919050565b7f4552433732313a2061646472657373207a65726f206973206e6f7420612076615f8201527f6c6964206f776e65720000000000000000000000000000000000000000000000602082015250565b5f613f23602983613195565b9150613f2e82613ec9565b604082019050919050565b5f6020820190508181035f830152613f5081613f17565b9050919050565b7f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e655f8201527f72206f7220617070726f76656400000000000000000000000000000000000000602082015250565b5f613fb1602d83613195565b9150613fbc82613f57565b604082019050919050565b5f6020820190508181035f830152613fde81613fa5565b9050919050565b5f81905092915050565b5f613ff98261318b565b6140038185613fe5565b93506140138185602086016131a5565b80840191505092915050565b5f61402a8286613fef565b91506140368285613fef565b91506140428284613fef565b9150819050949350505050565b5f6040820190506140625f8301856132c3565b61406f60208301846132c3565b9392505050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e655f8201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b5f6140d0602183613195565b91506140db82614076565b604082019050919050565b5f6020820190508181035f8301526140fd816140c4565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f5f8201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000602082015250565b5f61415e603d83613195565b915061416982614104565b604082019050919050565b5f6020820190508181035f83015261418b81614152565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e2045524337323152655f8201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b5f6141ec603283613195565b91506141f782614192565b604082019050919050565b5f6020820190508181035f830152614219816141e0565b9050919050565b7f4552433732313a207472616e736665722066726f6d20696e636f7272656374205f8201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b5f61427a602583613195565b915061428582614220565b604082019050919050565b5f6020820190508181035f8301526142a78161426e565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f614308602483613195565b9150614313826142ae565b604082019050919050565b5f6020820190508181035f830152614335816142fc565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c6572000000000000005f82015250565b5f614370601983613195565b915061437b8261433c565b602082019050919050565b5f6020820190508181035f83015261439d81614364565b9050919050565b5f81519050919050565b5f82825260208201905092915050565b5f6143c8826143a4565b6143d281856143ae565b93506143e28185602086016131a5565b6143eb816131cd565b840191505092915050565b5f6080820190506144095f8301876132c3565b61441660208301866132c3565b61442360408301856133c7565b818103606083015261443581846143be565b905095945050505050565b5f8151905061444e81613103565b92915050565b5f60208284031215614469576144686130d0565b5b5f61447684828501614440565b91505092915050565b7f4552433732313a206d696e7420746f20746865207a65726f20616464726573735f82015250565b5f6144b3602083613195565b91506144be8261447f565b602082019050919050565b5f6020820190508181035f8301526144e0816144a7565b9050919050565b7f4552433732313a20746f6b656e20616c7265616479206d696e746564000000005f82015250565b5f61451b601c83613195565b9150614526826144e7565b602082019050919050565b5f6020820190508181035f8301526145488161450f565b9050919050565b7f455243373231456e756d657261626c653a20636f6e73656375746976652074725f8201527f616e7366657273206e6f7420737570706f727465640000000000000000000000602082015250565b5f6145a9603583613195565b91506145b48261454f565b604082019050919050565b5f6020820190508181035f8301526145d68161459d565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea2646970667358221220b33bbdf69fe3fc3dffa8908864c177301ae8d1fb98204f8b3567fee043a3db2764736f6c63430008150033

Deployed Bytecode Sourcemap

88165:6503:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94204:230;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;63479:100;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;64991:171;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;88655:23;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92467:174;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;88623:25;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;91834:116;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;82402:113;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92653:180;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;18670:630;;;:::i;:::-;;82070:256;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;88271:80;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;89070:510;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;91419:97;;;;;;;;;;;;;:::i;:::-;;7863:143;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92841:188;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;82592:233;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92081:108;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;19385:466;;;:::i;:::-;;93588:104;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;89644:925;;;;;;;;;;;;;:::i;:::-;;63189:223;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;62920:207;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;18405:102;;;:::i;:::-;;91584:103;;;;;;;;;;;;;:::i;:::-;;94553:112;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;21110:196;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;63648:104;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;88440:80;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;88580:36;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92262:193;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;66285:279;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;88398:35;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;88527:46;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;88358:33;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;93945:251;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;90782:559;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;65460:164;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;88746:53;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;88691:48;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;20042:724;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;17979:358;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;21412:449;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;94204:230;94361:4;94390:36;94414:11;94390:23;:36::i;:::-;94383:43;;94204:230;;;:::o;63479:100::-;63533:13;63566:5;63559:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63479:100;:::o;64991:171::-;65067:7;65087:23;65102:7;65087:14;:23::i;:::-;65130:15;:24;65146:7;65130:24;;;;;;;;;;;;;;;;;;;;;65123:31;;64991:171;;;:::o;88655:23::-;;;;;;;;;;;;;:::o;92467:174::-;92580:8;9645:30;9666:8;9645:20;:30::i;:::-;92601:32:::1;92615:8;92625:7;92601:13;:32::i;:::-;92467:174:::0;;;:::o;88623:25::-;;;;:::o;91834:116::-;22258:13;:11;:13::i;:::-;91928::::1;91909:9;;:33;;;;;;;;;;;;;;;;;;91834:116:::0;:::o;82402:113::-;82463:7;82490:10;:17;;;;82483:24;;82402:113;:::o;92653:180::-;92771:4;9379:10;9371:18;;:4;:18;;;9367:83;;9406:32;9427:10;9406:20;:32::i;:::-;9367:83;92788:37:::1;92807:4;92813:2;92817:7;92788:18;:37::i;:::-;92653:180:::0;;;;:::o;18670:630::-;18765:15;18801:28;:26;:28::i;:::-;18783:46;;:15;:46;18765:64;;19001:19;18995:4;18988:33;19052:8;19046:4;19039:22;19109:7;19102:4;19096;19086:21;19079:38;19258:8;19211:45;19208:1;19205;19200:67;18901:381;18670:630::o;82070:256::-;82167:7;82203:23;82220:5;82203:16;:23::i;:::-;82195:5;:31;82187:87;;;;;;;;;;;;:::i;:::-;;;;;;;;;82292:12;:19;82305:5;82292:19;;;;;;;;;;;;;;;:26;82312:5;82292:26;;;;;;;;;;;;82285:33;;82070:256;;;;:::o;88271:80::-;88309:42;88271:80;:::o;89070:510::-;89160:13;;;;;;;;;;;89155:38;;89182:11;;;;;;;;;;;;;;89155:38;89249:9;89235:10;;89208:17;;:24;;:37;;;;:::i;:::-;:50;89204:77;;89267:14;;;;;;;;;;;;;;89204:77;89297:9;89292:281;89312:17;;:24;;89308:1;:28;89292:281;;;89412:10;89358:64;;88309:42;89358:28;;;89387:17;;89405:1;89387:20;;;;;;;:::i;:::-;;;;;;;;89358:50;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:64;;;89354:87;;89431:10;;;;;;;;;;;;;;89354:87;89456:43;89466:10;89478:17;;89496:1;89478:20;;;;;;;:::i;:::-;;;;;;;;89456:9;:43::i;:::-;89543:3;;;;;;;89292:281;;;;89070:510;;:::o;91419:97::-;22258:13;:11;:13::i;:::-;91495::::1;;;;;;;;;;;91494:14;91478:13;;:30;;;;;;;;;;;;;;;;;;91419:97::o:0;7863:143::-;337:42;7863:143;:::o;92841:188::-;92963:4;9379:10;9371:18;;:4;:18;;;9367:83;;9406:32;9427:10;9406:20;:32::i;:::-;9367:83;92980:41:::1;93003:4;93009:2;93013:7;92980:22;:41::i;:::-;92841:188:::0;;;;:::o;82592:233::-;82667:7;82703:30;:28;:30::i;:::-;82695:5;:38;82687:95;;;;;;;;;;;;:::i;:::-;;;;;;;;;82800:10;82811:5;82800:17;;;;;;;;:::i;:::-;;;;;;;;;;82793:24;;82592:233;;;:::o;92081:108::-;22258:13;:11;:13::i;:::-;92168::::1;92155:10;:26;;;;92081:108:::0;:::o;19385:466::-;19591:19;19585:4;19578:33;19638:8;19632:4;19625:22;19691:1;19684:4;19678;19668:21;19661:32;19824:8;19778:44;19775:1;19772;19767:66;19385:466::o;93588:104::-;22258:13;:11;:13::i;:::-;93673:11:::1;93663:7;:21;;;;;;:::i;:::-;;93588:104:::0;:::o;89644:925::-;89688:15;;;;;;;;;;;89683:45;;89712:16;;;;;;;;;;;;;;89683:45;89739:15;89757:23;89767:12;:10;:12::i;:::-;89757:9;:23::i;:::-;89739:41;;89806:1;89795:7;:12;89791:40;;89816:15;;;;;;;;;;;;;;89791:40;89852:23;89886:16;89905:17;:29;89923:10;89905:29;;;;;;;;;;;;;;;;89886:48;;89945:17;89965:15;89945:35;;90009:1;89997:8;:13;89993:265;;90051:9;90042:6;90031:8;:17;;;;:::i;:::-;:29;90027:58;;;90069:16;;;;;;;;;;;;;;90027:58;90154:1;90144:6;90132:8;90120:9;:20;;;;:::i;:::-;90119:31;;;;:::i;:::-;90118:37;;;;:::i;:::-;90100:55;;89993:265;;;90245:1;90235:6;90220:11;90208:9;:23;;;;:::i;:::-;90207:34;;;;:::i;:::-;90206:40;;;;:::i;:::-;90188:58;;89993:265;90302:9;90270:17;:29;90288:10;90270:29;;;;;;;;;;;;;;;:41;;;;90322:22;90365:7;90347:15;:25;;;;:::i;:::-;90322:50;;90436:14;90408:12;:24;90421:10;90408:24;;;;;;;;;;;;;;;;:42;;;;;;;;;;;90479:9;;;;;;;;;;;:18;;;90498:10;90527:8;90510:14;:25;;;;:::i;:::-;90479:57;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90474:87;;90545:16;;;;;;;;;;;;;;90474:87;89672:897;;;;;89644:925::o;63189:223::-;63261:7;63281:13;63297:17;63306:7;63297:8;:17::i;:::-;63281:33;;63350:1;63333:19;;:5;:19;;;63325:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;63399:5;63392:12;;;63189:223;;;:::o;62920:207::-;62992:7;63037:1;63020:19;;:5;:19;;;63012:73;;;;;;;;;;;;:::i;:::-;;;;;;;;;63103:9;:16;63113:5;63103:16;;;;;;;;;;;;;;;;63096:23;;62920:207;;;:::o;18405:102::-;22258:13;:11;:13::i;:::-;18478:21:::1;18496:1;18478:9;:21::i;:::-;18405:102::o:0;91584:103::-;22258:13;:11;:13::i;:::-;91664:15:::1;;;;;;;;;;;91663:16;91645:15;;:34;;;;;;;;;;;;;;;;;;91584:103::o:0;94553:112::-;22258:13;:11;:13::i;:::-;94619:9:::1;;;;;;;;;;;:18;;;94638:10;94650:6;94619:38;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;94553:112:::0;:::o;21110:196::-;21156:14;21271:15;21267:20;21261:27;21251:37;;21110:196;:::o;63648:104::-;63704:13;63737:7;63730:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63648:104;:::o;88440:80::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;88580:36::-;;;:::o;92262:193::-;92383:8;9645:30;9666:8;9645:20;:30::i;:::-;92404:43:::1;92428:8;92438;92404:23;:43::i;:::-;92262:193:::0;;;:::o;66285:279::-;66416:41;66435:12;:10;:12::i;:::-;66449:7;66416:18;:41::i;:::-;66408:99;;;;;;;;;;;;:::i;:::-;;;;;;;;;66518:38;66532:4;66538:2;66542:7;66551:4;66518:13;:38::i;:::-;66285:279;;;;:::o;88398:35::-;;;;;;;;;;;;;:::o;88527:46::-;;;;;;;;;;;;;;;;;;;:::o;88358:33::-;;;;;;;;;;;;;:::o;93945:251::-;94072:13;94134:10;:8;:10::i;:::-;94146:25;94163:7;94146:16;:25::i;:::-;94173:13;;;;;;;;;;;;;;;;;94117:70;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;94103:85;;93945:251;;;:::o;90782:559::-;90852:7;90872:15;90890:23;90900:12;:10;:12::i;:::-;90890:9;:23::i;:::-;90872:41;;90924:17;90944:15;90924:35;;90985:1;90974:7;:12;90970:26;;90995:1;90988:8;;;;;;90970:26;91007:23;91041:13;91057:17;:27;91075:8;91057:27;;;;;;;;;;;;;;;;91041:43;;91108:1;91099:5;:10;91095:142;;91162:1;91152:6;91143:5;91131:9;:17;;;;:::i;:::-;91130:28;;;;:::i;:::-;91129:34;;;;:::i;:::-;91111:52;;91095:142;;;91236:1;91226:6;91211:11;91199:9;:23;;;;:::i;:::-;91198:34;;;;:::i;:::-;91197:40;;;;:::i;:::-;91179:58;;91095:142;91250:17;91288:7;91270:15;:25;;;;:::i;:::-;91250:45;;91325:8;91313:9;:20;;;;:::i;:::-;91306:27;;;;;;;90782:559;;;;:::o;65460:164::-;65557:4;65581:18;:25;65600:5;65581:25;;;;;;;;;;;;;;;:35;65607:8;65581:35;;;;;;;;;;;;;;;;;;;;;;;;;65574:42;;65460:164;;;;:::o;88746:53::-;;;;;;;;;;;;;;;;;:::o;88691:48::-;;;;;;;;;;;;;;;;;:::o;20042:724::-;22258:13;:11;:13::i;:::-;20280:19:::1;20274:4;20267:33;20327:12;20321:4;20314:26;20390:4;20384;20374:21;20498:12;20492:19;20479:11;20476:36;20473:160;;;20545:10;20539:4;20532:24;20613:4;20607;20600:18;20473:160;20712:1;20698:12;20691:23;20196:529;20735:23;20745:12;20735:9;:23::i;:::-;20042:724:::0;:::o;17979:358::-;22258:13;:11;:13::i;:::-;18154:8:::1;18150:2;18146:17;18136:153;;18197:10;18191:4;18184:24;18269:4;18263;18256:18;18136:153;18310:19;18320:8;18310:9;:19::i;:::-;17979:358:::0;:::o;21412:449::-;21535:14;21691:19;21685:4;21678:33;21738:12;21732:4;21725:26;21837:4;21831;21821:21;21815:28;21805:38;;21412:449;;;:::o;78942:207::-;79044:4;79090:10;79083:18;;79068:33;;;:11;:33;;;;:73;;;;79105:36;79129:11;79105:23;:36::i;:::-;79068:73;79061:80;;78942:207;;;:::o;74554:135::-;74636:16;74644:7;74636;:16::i;:::-;74628:53;;;;;;;;;;;;:::i;:::-;;;;;;;;;74554:135;:::o;9788:647::-;10027:1;337:42;9979:45;;;:49;9975:453;;;337:42;10278;;;10329:4;10336:8;10278:67;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10273:144;;10392:8;10373:28;;;;;;;;;;;:::i;:::-;;;;;;;;10273:144;9975:453;9788:647;:::o;64509:416::-;64590:13;64606:23;64621:7;64606:14;:23::i;:::-;64590:39;;64654:5;64648:11;;:2;:11;;;64640:57;;;;;;;;;;;;:::i;:::-;;;;;;;;;64748:5;64732:21;;:12;:10;:12::i;:::-;:21;;;:62;;;;64757:37;64774:5;64781:12;:10;:12::i;:::-;64757:16;:37::i;:::-;64732:62;64710:173;;;;;;;;;;;;:::i;:::-;;;;;;;;;64896:21;64905:2;64909:7;64896:8;:21::i;:::-;64579:346;64509:416;;:::o;16891:373::-;17111:15;17107:20;17101:27;17091:8;17088:41;17078:168;;17163:10;17157:4;17150:24;17226:4;17220;17213:18;17078:168;16891:373::o;65691:301::-;65852:41;65871:12;:10;:12::i;:::-;65885:7;65852:18;:41::i;:::-;65844:99;;;;;;;;;;;;:::i;:::-;;;;;;;;;65956:28;65966:4;65972:2;65976:7;65956:9;:28::i;:::-;65691:301;;;:::o;17500:112::-;17569:6;17595:9;17588:16;;17500:112;:::o;69160:110::-;69236:26;69246:2;69250:7;69236:26;;;;;;;;;;;;:9;:26::i;:::-;69160:110;;:::o;66063:151::-;66167:39;66184:4;66190:2;66194:7;66167:39;;;;;;;;;;;;:16;:39::i;:::-;66063:151;;;:::o;40297:98::-;40350:7;40377:10;40370:17;;40297:98;:::o;67829:117::-;67895:7;67922;:16;67930:7;67922:16;;;;;;;;;;;;;;;;;;;;;67915:23;;67829:117;;;:::o;16324:506::-;16478:15;16474:20;16577:8;16573:2;16569:17;16565:2;16561:26;16549:38;;16725:8;16713:9;16707:16;16667:38;16664:1;16661;16656:78;16803:8;16792:9;16785:27;16442:381;16324:506;:::o;65234:155::-;65329:52;65348:12;:10;:12::i;:::-;65362:8;65372;65329:18;:52::i;:::-;65234:155;;:::o;68554:264::-;68647:4;68664:13;68680:23;68695:7;68680:14;:23::i;:::-;68664:39;;68733:5;68722:16;;:7;:16;;;:52;;;;68742:32;68759:5;68766:7;68742:16;:32::i;:::-;68722:52;:87;;;;68802:7;68778:31;;:20;68790:7;68778:11;:20::i;:::-;:31;;;68722:87;68714:96;;;68554:264;;;;:::o;67445:270::-;67558:28;67568:4;67574:2;67578:7;67558:9;:28::i;:::-;67605:47;67628:4;67634:2;67638:7;67647:4;67605:22;:47::i;:::-;67597:110;;;;;;;;;;;;:::i;:::-;;;;;;;;;67445:270;;;;:::o;93734:100::-;93786:13;93819:7;93812:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93734:100;:::o;37216:716::-;37272:13;37323:14;37360:1;37340:17;37351:5;37340:10;:17::i;:::-;:21;37323:38;;37376:20;37410:6;37399:18;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37376:41;;37432:11;37561:6;37557:2;37553:15;37545:6;37541:28;37534:35;;37598:288;37605:4;37598:288;;;37630:5;;;;;;;;37772:8;37767:2;37760:5;37756:14;37751:30;37746:3;37738:44;37828:2;37819:11;;;;;;:::i;:::-;;;;;37862:1;37853:5;:10;37598:288;37849:21;37598:288;37907:6;37900:13;;;;;37216:716;;;:::o;81762:224::-;81864:4;81903:35;81888:50;;;:11;:50;;;;:90;;;;81942:36;81966:11;81942:23;:36::i;:::-;81888:90;81881:97;;81762:224;;;:::o;68259:128::-;68324:4;68377:1;68348:31;;:17;68357:7;68348:8;:17::i;:::-;:31;;;;68341:38;;68259:128;;;:::o;73867:174::-;73969:2;73942:15;:24;73958:7;73942:24;;;;;;;;;;;;:29;;;;;;;;;;;;;;;;;;74025:7;74021:2;73987:46;;73996:23;74011:7;73996:14;:23::i;:::-;73987:46;;;;;;;;;;;;73867:174;;:::o;72519:1229::-;72644:4;72617:31;;:23;72632:7;72617:14;:23::i;:::-;:31;;;72609:81;;;;;;;;;;;;:::i;:::-;;;;;;;;;72723:1;72709:16;;:2;:16;;;72701:65;;;;;;;;;;;;:::i;:::-;;;;;;;;;72779:42;72800:4;72806:2;72810:7;72819:1;72779:20;:42::i;:::-;72951:4;72924:31;;:23;72939:7;72924:14;:23::i;:::-;:31;;;72916:81;;;;;;;;;;;;:::i;:::-;;;;;;;;;73069:15;:24;73085:7;73069:24;;;;;;;;;;;;73062:31;;;;;;;;;;;73564:1;73545:9;:15;73555:4;73545:15;;;;;;;;;;;;;;;;:20;;;;;;;;;;;73597:1;73580:9;:13;73590:2;73580:13;;;;;;;;;;;;;;;;:18;;;;;;;;;;;73639:2;73620:7;:16;73628:7;73620:16;;;;;;;;;;;;:21;;;;;;;;;;;;;;;;;;73678:7;73674:2;73659:27;;73668:4;73659:27;;;;;;;;;;;;73699:41;73719:4;73725:2;73729:7;73738:1;73699:19;:41::i;:::-;72519:1229;;;:::o;69497:285::-;69592:18;69598:2;69602:7;69592:5;:18::i;:::-;69643:53;69674:1;69678:2;69682:7;69691:4;69643:22;:53::i;:::-;69621:153;;;;;;;;;;;;:::i;:::-;;;;;;;;;69497:285;;;:::o;74184:281::-;74305:8;74296:17;;:5;:17;;;74288:55;;;;;;;;;;;;:::i;:::-;;;;;;;;;74392:8;74354:18;:25;74373:5;74354:25;;;;;;;;;;;;;;;:35;74380:8;74354:35;;;;;;;;;;;;;;;;:46;;;;;;;;;;;;;;;;;;74438:8;74416:41;;74431:5;74416:41;;;74448:8;74416:41;;;;;;:::i;:::-;;;;;;;;74184:281;;;:::o;75253:853::-;75407:4;75428:15;:2;:13;;;:15::i;:::-;75424:675;;;75480:2;75464:36;;;75501:12;:10;:12::i;:::-;75515:4;75521:7;75530:4;75464:71;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;75460:584;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75722:1;75705:6;:13;:18;75701:328;;75748:60;;;;;;;;;;:::i;:::-;;;;;;;;75701:328;75979:6;75973:13;75964:6;75960:2;75956:15;75949:38;75460:584;75596:41;;;75586:51;;;:6;:51;;;;75579:58;;;;;75424:675;76083:4;76076:11;;75253:853;;;;;;;:::o;34050:948::-;34103:7;34123:14;34140:1;34123:18;;34190:8;34181:5;:17;34177:106;;34228:8;34219:17;;;;;;:::i;:::-;;;;;34265:2;34255:12;;;;34177:106;34310:8;34301:5;:17;34297:106;;34348:8;34339:17;;;;;;:::i;:::-;;;;;34385:2;34375:12;;;;34297:106;34430:8;34421:5;:17;34417:106;;34468:8;34459:17;;;;;;:::i;:::-;;;;;34505:2;34495:12;;;;34417:106;34550:7;34541:5;:16;34537:103;;34587:7;34578:16;;;;;;:::i;:::-;;;;;34623:1;34613:11;;;;34537:103;34667:7;34658:5;:16;34654:103;;34704:7;34695:16;;;;;;:::i;:::-;;;;;34740:1;34730:11;;;;34654:103;34784:7;34775:5;:16;34771:103;;34821:7;34812:16;;;;;;:::i;:::-;;;;;34857:1;34847:11;;;;34771:103;34901:7;34892:5;:16;34888:68;;34939:1;34929:11;;;;34888:68;34984:6;34977:13;;;34050:948;;;:::o;62551:305::-;62653:4;62705:25;62690:40;;;:11;:40;;;;:105;;;;62762:33;62747:48;;;:11;:48;;;;62690:105;:158;;;;62812:36;62836:11;62812:23;:36::i;:::-;62690:158;62670:178;;62551:305;;;:::o;93105:234::-;93275:56;93302:4;93308:2;93312:7;93321:9;93275:26;:56::i;:::-;93105:234;;;;:::o;77676:115::-;;;;;:::o;70118:942::-;70212:1;70198:16;;:2;:16;;;70190:61;;;;;;;;;;;;:::i;:::-;;;;;;;;;70271:16;70279:7;70271;:16::i;:::-;70270:17;70262:58;;;;;;;;;;;;:::i;:::-;;;;;;;;;70333:48;70362:1;70366:2;70370:7;70379:1;70333:20;:48::i;:::-;70480:16;70488:7;70480;:16::i;:::-;70479:17;70471:58;;;;;;;;;;;;:::i;:::-;;;;;;;;;70895:1;70878:9;:13;70888:2;70878:13;;;;;;;;;;;;;;;;:18;;;;;;;;;;;70939:2;70920:7;:16;70928:7;70920:16;;;;;;;;;;;;:21;;;;;;;;;;;;;;;;;;70984:7;70980:2;70959:33;;70976:1;70959:33;;;;;;;;;;;;71005:47;71033:1;71037:2;71041:7;71050:1;71005:19;:47::i;:::-;70118:942;;:::o;41985:326::-;42045:4;42302:1;42280:7;:19;;;:23;42273:30;;41985:326;;;:::o;53131:157::-;53216:4;53255:25;53240:40;;;:11;:40;;;;53233:47;;53131:157;;;:::o;82899:915::-;83076:61;83103:4;83109:2;83113:12;83127:9;83076:26;:61::i;:::-;83166:1;83154:9;:13;83150:222;;;83297:63;;;;;;;;;;:::i;:::-;;;;;;;;83150:222;83384:15;83402:12;83384:30;;83447:1;83431:18;;:4;:18;;;83427:187;;83466:40;83498:7;83466:31;:40::i;:::-;83427:187;;;83536:2;83528:10;;:4;:10;;;83524:90;;83555:47;83588:4;83594:7;83555:32;:47::i;:::-;83524:90;83427:187;83642:1;83628:16;;:2;:16;;;83624:183;;83661:45;83698:7;83661:36;:45::i;:::-;83624:183;;;83734:4;83728:10;;:2;:10;;;83724:83;;83755:40;83783:2;83787:7;83755:27;:40::i;:::-;83724:83;83624:183;83065:749;82899:915;;;;:::o;76838:116::-;;;;;:::o;84537:164::-;84641:10;:17;;;;84614:15;:24;84630:7;84614:24;;;;;;;;;;;:44;;;;84669:10;84685:7;84669:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84537:164;:::o;85328:988::-;85594:22;85644:1;85619:22;85636:4;85619:16;:22::i;:::-;:26;;;;:::i;:::-;85594:51;;85656:18;85677:17;:26;85695:7;85677:26;;;;;;;;;;;;85656:47;;85824:14;85810:10;:28;85806:328;;85855:19;85877:12;:18;85890:4;85877:18;;;;;;;;;;;;;;;:34;85896:14;85877:34;;;;;;;;;;;;85855:56;;85961:11;85928:12;:18;85941:4;85928:18;;;;;;;;;;;;;;;:30;85947:10;85928:30;;;;;;;;;;;:44;;;;86078:10;86045:17;:30;86063:11;86045:30;;;;;;;;;;;:43;;;;85840:294;85806:328;86230:17;:26;86248:7;86230:26;;;;;;;;;;;86223:33;;;86274:12;:18;86287:4;86274:18;;;;;;;;;;;;;;;:34;86293:14;86274:34;;;;;;;;;;;86267:41;;;85409:907;;85328:988;;:::o;86611:1079::-;86864:22;86909:1;86889:10;:17;;;;:21;;;;:::i;:::-;86864:46;;86921:18;86942:15;:24;86958:7;86942:24;;;;;;;;;;;;86921:45;;87293:19;87315:10;87326:14;87315:26;;;;;;;;:::i;:::-;;;;;;;;;;87293:48;;87379:11;87354:10;87365;87354:22;;;;;;;;:::i;:::-;;;;;;;;;:36;;;;87490:10;87459:15;:28;87475:11;87459:28;;;;;;;;;;;:41;;;;87631:15;:24;87647:7;87631:24;;;;;;;;;;;87624:31;;;87666:10;:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;86682:1008;;;86611:1079;:::o;84115:221::-;84200:14;84217:20;84234:2;84217:16;:20::i;:::-;84200:37;;84275:7;84248:12;:16;84261:2;84248:16;;;;;;;;;;;;;;;:24;84265:6;84248:24;;;;;;;;;;;:34;;;;84322:6;84293:17;:26;84311:7;84293:26;;;;;;;;;;;:35;;;;84189:147;84115:221;;:::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:99::-;1570:6;1604:5;1598:12;1588:22;;1518:99;;;:::o;1623:169::-;1707:11;1741:6;1736:3;1729:19;1781:4;1776:3;1772:14;1757:29;;1623:169;;;;:::o;1798:246::-;1879:1;1889:113;1903:6;1900:1;1897:13;1889:113;;;1988:1;1983:3;1979:11;1973:18;1969:1;1964:3;1960:11;1953:39;1925:2;1922:1;1918:10;1913:15;;1889:113;;;2036:1;2027:6;2022:3;2018:16;2011:27;1860:184;1798:246;;;:::o;2050:102::-;2091:6;2142:2;2138:7;2133:2;2126:5;2122:14;2118:28;2108:38;;2050:102;;;:::o;2158:377::-;2246:3;2274:39;2307:5;2274:39;:::i;:::-;2329:71;2393:6;2388:3;2329:71;:::i;:::-;2322:78;;2409:65;2467:6;2462:3;2455:4;2448:5;2444:16;2409:65;:::i;:::-;2499:29;2521:6;2499:29;:::i;:::-;2494:3;2490:39;2483:46;;2250:285;2158:377;;;;:::o;2541:313::-;2654:4;2692:2;2681:9;2677:18;2669:26;;2741:9;2735:4;2731:20;2727:1;2716:9;2712:17;2705:47;2769:78;2842:4;2833:6;2769:78;:::i;:::-;2761:86;;2541:313;;;;:::o;2860:77::-;2897:7;2926:5;2915:16;;2860:77;;;:::o;2943:122::-;3016:24;3034:5;3016:24;:::i;:::-;3009:5;3006:35;2996:63;;3055:1;3052;3045:12;2996:63;2943:122;:::o;3071:139::-;3117:5;3155:6;3142:20;3133:29;;3171:33;3198:5;3171:33;:::i;:::-;3071:139;;;;:::o;3216:329::-;3275:6;3324:2;3312:9;3303:7;3299:23;3295:32;3292:119;;;3330:79;;:::i;:::-;3292:119;3450:1;3475:53;3520:7;3511:6;3500:9;3496:22;3475:53;:::i;:::-;3465:63;;3421:117;3216:329;;;;:::o;3551:126::-;3588:7;3628:42;3621:5;3617:54;3606:65;;3551:126;;;:::o;3683:96::-;3720:7;3749:24;3767:5;3749:24;:::i;:::-;3738:35;;3683:96;;;:::o;3785:118::-;3872:24;3890:5;3872:24;:::i;:::-;3867:3;3860:37;3785:118;;:::o;3909:222::-;4002:4;4040:2;4029:9;4025:18;4017:26;;4053:71;4121:1;4110:9;4106:17;4097:6;4053:71;:::i;:::-;3909:222;;;;:::o;4137:60::-;4165:3;4186:5;4179:12;;4137:60;;;:::o;4203:142::-;4253:9;4286:53;4304:34;4313:24;4331:5;4313:24;:::i;:::-;4304:34;:::i;:::-;4286:53;:::i;:::-;4273:66;;4203:142;;;:::o;4351:126::-;4401:9;4434:37;4465:5;4434:37;:::i;:::-;4421:50;;4351:126;;;:::o;4483:141::-;4548:9;4581:37;4612:5;4581:37;:::i;:::-;4568:50;;4483:141;;;:::o;4630:161::-;4732:52;4778:5;4732:52;:::i;:::-;4727:3;4720:65;4630:161;;:::o;4797:252::-;4905:4;4943:2;4932:9;4928:18;4920:26;;4956:86;5039:1;5028:9;5024:17;5015:6;4956:86;:::i;:::-;4797:252;;;;:::o;5055:122::-;5128:24;5146:5;5128:24;:::i;:::-;5121:5;5118:35;5108:63;;5167:1;5164;5157:12;5108:63;5055:122;:::o;5183:139::-;5229:5;5267:6;5254:20;5245:29;;5283:33;5310:5;5283:33;:::i;:::-;5183:139;;;;:::o;5328:474::-;5396:6;5404;5453:2;5441:9;5432:7;5428:23;5424:32;5421:119;;;5459:79;;:::i;:::-;5421:119;5579:1;5604:53;5649:7;5640:6;5629:9;5625:22;5604:53;:::i;:::-;5594:63;;5550:117;5706:2;5732:53;5777:7;5768:6;5757:9;5753:22;5732:53;:::i;:::-;5722:63;;5677:118;5328:474;;;;;:::o;5808:118::-;5895:24;5913:5;5895:24;:::i;:::-;5890:3;5883:37;5808:118;;:::o;5932:222::-;6025:4;6063:2;6052:9;6048:18;6040:26;;6076:71;6144:1;6133:9;6129:17;6120:6;6076:71;:::i;:::-;5932:222;;;;:::o;6160:329::-;6219:6;6268:2;6256:9;6247:7;6243:23;6239:32;6236:119;;;6274:79;;:::i;:::-;6236:119;6394:1;6419:53;6464:7;6455:6;6444:9;6440:22;6419:53;:::i;:::-;6409:63;;6365:117;6160:329;;;;:::o;6495:619::-;6572:6;6580;6588;6637:2;6625:9;6616:7;6612:23;6608:32;6605:119;;;6643:79;;:::i;:::-;6605:119;6763:1;6788:53;6833:7;6824:6;6813:9;6809:22;6788:53;:::i;:::-;6778:63;;6734:117;6890:2;6916:53;6961:7;6952:6;6941:9;6937:22;6916:53;:::i;:::-;6906:63;;6861:118;7018:2;7044:53;7089:7;7080:6;7069:9;7065:22;7044:53;:::i;:::-;7034:63;;6989:118;6495:619;;;;;:::o;7120:117::-;7229:1;7226;7219:12;7243:117;7352:1;7349;7342:12;7366:117;7475:1;7472;7465:12;7506:568;7579:8;7589:6;7639:3;7632:4;7624:6;7620:17;7616:27;7606:122;;7647:79;;:::i;:::-;7606:122;7760:6;7747:20;7737:30;;7790:18;7782:6;7779:30;7776:117;;;7812:79;;:::i;:::-;7776:117;7926:4;7918:6;7914:17;7902:29;;7980:3;7972:4;7964:6;7960:17;7950:8;7946:32;7943:41;7940:128;;;7987:79;;:::i;:::-;7940:128;7506:568;;;;;:::o;8080:559::-;8166:6;8174;8223:2;8211:9;8202:7;8198:23;8194:32;8191:119;;;8229:79;;:::i;:::-;8191:119;8377:1;8366:9;8362:17;8349:31;8407:18;8399:6;8396:30;8393:117;;;8429:79;;:::i;:::-;8393:117;8542:80;8614:7;8605:6;8594:9;8590:22;8542:80;:::i;:::-;8524:98;;;;8320:312;8080:559;;;;;:::o;8645:157::-;8726:9;8759:37;8790:5;8759:37;:::i;:::-;8746:50;;8645:157;;;:::o;8808:193::-;8926:68;8988:5;8926:68;:::i;:::-;8921:3;8914:81;8808:193;;:::o;9007:284::-;9131:4;9169:2;9158:9;9154:18;9146:26;;9182:102;9281:1;9270:9;9266:17;9257:6;9182:102;:::i;:::-;9007:284;;;;:::o;9297:117::-;9406:1;9403;9396:12;9420:180;9468:77;9465:1;9458:88;9565:4;9562:1;9555:15;9589:4;9586:1;9579:15;9606:281;9689:27;9711:4;9689:27;:::i;:::-;9681:6;9677:40;9819:6;9807:10;9804:22;9783:18;9771:10;9768:34;9765:62;9762:88;;;9830:18;;:::i;:::-;9762:88;9870:10;9866:2;9859:22;9649:238;9606:281;;:::o;9893:129::-;9927:6;9954:20;;:::i;:::-;9944:30;;9983:33;10011:4;10003:6;9983:33;:::i;:::-;9893:129;;;:::o;10028:308::-;10090:4;10180:18;10172:6;10169:30;10166:56;;;10202:18;;:::i;:::-;10166:56;10240:29;10262:6;10240:29;:::i;:::-;10232:37;;10324:4;10318;10314:15;10306:23;;10028:308;;;:::o;10342:146::-;10439:6;10434:3;10429;10416:30;10480:1;10471:6;10466:3;10462:16;10455:27;10342:146;;;:::o;10494:425::-;10572:5;10597:66;10613:49;10655:6;10613:49;:::i;:::-;10597:66;:::i;:::-;10588:75;;10686:6;10679:5;10672:21;10724:4;10717:5;10713:16;10762:3;10753:6;10748:3;10744:16;10741:25;10738:112;;;10769:79;;:::i;:::-;10738:112;10859:54;10906:6;10901:3;10896;10859:54;:::i;:::-;10578:341;10494:425;;;;;:::o;10939:340::-;10995:5;11044:3;11037:4;11029:6;11025:17;11021:27;11011:122;;11052:79;;:::i;:::-;11011:122;11169:6;11156:20;11194:79;11269:3;11261:6;11254:4;11246:6;11242:17;11194:79;:::i;:::-;11185:88;;11001:278;10939:340;;;;:::o;11285:509::-;11354:6;11403:2;11391:9;11382:7;11378:23;11374:32;11371:119;;;11409:79;;:::i;:::-;11371:119;11557:1;11546:9;11542:17;11529:31;11587:18;11579:6;11576:30;11573:117;;;11609:79;;:::i;:::-;11573:117;11714:63;11769:7;11760:6;11749:9;11745:22;11714:63;:::i;:::-;11704:73;;11500:287;11285:509;;;;:::o;11800:116::-;11870:21;11885:5;11870:21;:::i;:::-;11863:5;11860:32;11850:60;;11906:1;11903;11896:12;11850:60;11800:116;:::o;11922:133::-;11965:5;12003:6;11990:20;11981:29;;12019:30;12043:5;12019:30;:::i;:::-;11922:133;;;;:::o;12061:468::-;12126:6;12134;12183:2;12171:9;12162:7;12158:23;12154:32;12151:119;;;12189:79;;:::i;:::-;12151:119;12309:1;12334:53;12379:7;12370:6;12359:9;12355:22;12334:53;:::i;:::-;12324:63;;12280:117;12436:2;12462:50;12504:7;12495:6;12484:9;12480:22;12462:50;:::i;:::-;12452:60;;12407:115;12061:468;;;;;:::o;12535:307::-;12596:4;12686:18;12678:6;12675:30;12672:56;;;12708:18;;:::i;:::-;12672:56;12746:29;12768:6;12746:29;:::i;:::-;12738:37;;12830:4;12824;12820:15;12812:23;;12535:307;;;:::o;12848:423::-;12925:5;12950:65;12966:48;13007:6;12966:48;:::i;:::-;12950:65;:::i;:::-;12941:74;;13038:6;13031:5;13024:21;13076:4;13069:5;13065:16;13114:3;13105:6;13100:3;13096:16;13093:25;13090:112;;;13121:79;;:::i;:::-;13090:112;13211:54;13258:6;13253:3;13248;13211:54;:::i;:::-;12931:340;12848:423;;;;;:::o;13290:338::-;13345:5;13394:3;13387:4;13379:6;13375:17;13371:27;13361:122;;13402:79;;:::i;:::-;13361:122;13519:6;13506:20;13544:78;13618:3;13610:6;13603:4;13595:6;13591:17;13544:78;:::i;:::-;13535:87;;13351:277;13290:338;;;;:::o;13634:943::-;13729:6;13737;13745;13753;13802:3;13790:9;13781:7;13777:23;13773:33;13770:120;;;13809:79;;:::i;:::-;13770:120;13929:1;13954:53;13999:7;13990:6;13979:9;13975:22;13954:53;:::i;:::-;13944:63;;13900:117;14056:2;14082:53;14127:7;14118:6;14107:9;14103:22;14082:53;:::i;:::-;14072:63;;14027:118;14184:2;14210:53;14255:7;14246:6;14235:9;14231:22;14210:53;:::i;:::-;14200:63;;14155:118;14340:2;14329:9;14325:18;14312:32;14371:18;14363:6;14360:30;14357:117;;;14393:79;;:::i;:::-;14357:117;14498:62;14552:7;14543:6;14532:9;14528:22;14498:62;:::i;:::-;14488:72;;14283:287;13634:943;;;;;;;:::o;14583:474::-;14651:6;14659;14708:2;14696:9;14687:7;14683:23;14679:32;14676:119;;;14714:79;;:::i;:::-;14676:119;14834:1;14859:53;14904:7;14895:6;14884:9;14880:22;14859:53;:::i;:::-;14849:63;;14805:117;14961:2;14987:53;15032:7;15023:6;15012:9;15008:22;14987:53;:::i;:::-;14977:63;;14932:118;14583:474;;;;;:::o;15063:180::-;15111:77;15108:1;15101:88;15208:4;15205:1;15198:15;15232:4;15229:1;15222:15;15249:320;15293:6;15330:1;15324:4;15320:12;15310:22;;15377:1;15371:4;15367:12;15398:18;15388:81;;15454:4;15446:6;15442:17;15432:27;;15388:81;15516:2;15508:6;15505:14;15485:18;15482:38;15479:84;;15535:18;;:::i;:::-;15479:84;15300:269;15249:320;;;:::o;15575:230::-;15715:34;15711:1;15703:6;15699:14;15692:58;15784:13;15779:2;15771:6;15767:15;15760:38;15575:230;:::o;15811:366::-;15953:3;15974:67;16038:2;16033:3;15974:67;:::i;:::-;15967:74;;16050:93;16139:3;16050:93;:::i;:::-;16168:2;16163:3;16159:12;16152:19;;15811:366;;;:::o;16183:419::-;16349:4;16387:2;16376:9;16372:18;16364:26;;16436:9;16430:4;16426:20;16422:1;16411:9;16407:17;16400:47;16464:131;16590:4;16464:131;:::i;:::-;16456:139;;16183:419;;;:::o;16608:180::-;16656:77;16653:1;16646:88;16753:4;16750:1;16743:15;16777:4;16774:1;16767:15;16794:410;16834:7;16857:20;16875:1;16857:20;:::i;:::-;16852:25;;16891:20;16909:1;16891:20;:::i;:::-;16886:25;;16946:1;16943;16939:9;16968:30;16986:11;16968:30;:::i;:::-;16957:41;;17147:1;17138:7;17134:15;17131:1;17128:22;17108:1;17101:9;17081:83;17058:139;;17177:18;;:::i;:::-;17058:139;16842:362;16794:410;;;;:::o;17210:180::-;17258:77;17255:1;17248:88;17355:4;17352:1;17345:15;17379:4;17376:1;17369:15;17396:143;17453:5;17484:6;17478:13;17469:22;;17500:33;17527:5;17500:33;:::i;:::-;17396:143;;;;:::o;17545:351::-;17615:6;17664:2;17652:9;17643:7;17639:23;17635:32;17632:119;;;17670:79;;:::i;:::-;17632:119;17790:1;17815:64;17871:7;17862:6;17851:9;17847:22;17815:64;:::i;:::-;17805:74;;17761:128;17545:351;;;;:::o;17902:231::-;18042:34;18038:1;18030:6;18026:14;18019:58;18111:14;18106:2;18098:6;18094:15;18087:39;17902:231;:::o;18139:366::-;18281:3;18302:67;18366:2;18361:3;18302:67;:::i;:::-;18295:74;;18378:93;18467:3;18378:93;:::i;:::-;18496:2;18491:3;18487:12;18480:19;;18139:366;;;:::o;18511:419::-;18677:4;18715:2;18704:9;18700:18;18692:26;;18764:9;18758:4;18754:20;18750:1;18739:9;18735:17;18728:47;18792:131;18918:4;18792:131;:::i;:::-;18784:139;;18511:419;;;:::o;18936:141::-;18985:4;19008:3;19000:11;;19031:3;19028:1;19021:14;19065:4;19062:1;19052:18;19044:26;;18936:141;;;:::o;19083:93::-;19120:6;19167:2;19162;19155:5;19151:14;19147:23;19137:33;;19083:93;;;:::o;19182:107::-;19226:8;19276:5;19270:4;19266:16;19245:37;;19182:107;;;;:::o;19295:393::-;19364:6;19414:1;19402:10;19398:18;19437:97;19467:66;19456:9;19437:97;:::i;:::-;19555:39;19585:8;19574:9;19555:39;:::i;:::-;19543:51;;19627:4;19623:9;19616:5;19612:21;19603:30;;19676:4;19666:8;19662:19;19655:5;19652:30;19642:40;;19371:317;;19295:393;;;;;:::o;19694:142::-;19744:9;19777:53;19795:34;19804:24;19822:5;19804:24;:::i;:::-;19795:34;:::i;:::-;19777:53;:::i;:::-;19764:66;;19694:142;;;:::o;19842:75::-;19885:3;19906:5;19899:12;;19842:75;;;:::o;19923:269::-;20033:39;20064:7;20033:39;:::i;:::-;20094:91;20143:41;20167:16;20143:41;:::i;:::-;20135:6;20128:4;20122:11;20094:91;:::i;:::-;20088:4;20081:105;19999:193;19923:269;;;:::o;20198:73::-;20243:3;20198:73;:::o;20277:189::-;20354:32;;:::i;:::-;20395:65;20453:6;20445;20439:4;20395:65;:::i;:::-;20330:136;20277:189;;:::o;20472:186::-;20532:120;20549:3;20542:5;20539:14;20532:120;;;20603:39;20640:1;20633:5;20603:39;:::i;:::-;20576:1;20569:5;20565:13;20556:22;;20532:120;;;20472:186;;:::o;20664:543::-;20765:2;20760:3;20757:11;20754:446;;;20799:38;20831:5;20799:38;:::i;:::-;20883:29;20901:10;20883:29;:::i;:::-;20873:8;20869:44;21066:2;21054:10;21051:18;21048:49;;;21087:8;21072:23;;21048:49;21110:80;21166:22;21184:3;21166:22;:::i;:::-;21156:8;21152:37;21139:11;21110:80;:::i;:::-;20769:431;;20754:446;20664:543;;;:::o;21213:117::-;21267:8;21317:5;21311:4;21307:16;21286:37;;21213:117;;;;:::o;21336:169::-;21380:6;21413:51;21461:1;21457:6;21449:5;21446:1;21442:13;21413:51;:::i;:::-;21409:56;21494:4;21488;21484:15;21474:25;;21387:118;21336:169;;;;:::o;21510:295::-;21586:4;21732:29;21757:3;21751:4;21732:29;:::i;:::-;21724:37;;21794:3;21791:1;21787:11;21781:4;21778:21;21770:29;;21510:295;;;;:::o;21810:1395::-;21927:37;21960:3;21927:37;:::i;:::-;22029:18;22021:6;22018:30;22015:56;;;22051:18;;:::i;:::-;22015:56;22095:38;22127:4;22121:11;22095:38;:::i;:::-;22180:67;22240:6;22232;22226:4;22180:67;:::i;:::-;22274:1;22298:4;22285:17;;22330:2;22322:6;22319:14;22347:1;22342:618;;;;23004:1;23021:6;23018:77;;;23070:9;23065:3;23061:19;23055:26;23046:35;;23018:77;23121:67;23181:6;23174:5;23121:67;:::i;:::-;23115:4;23108:81;22977:222;22312:887;;22342:618;22394:4;22390:9;22382:6;22378:22;22428:37;22460:4;22428:37;:::i;:::-;22487:1;22501:208;22515:7;22512:1;22509:14;22501:208;;;22594:9;22589:3;22585:19;22579:26;22571:6;22564:42;22645:1;22637:6;22633:14;22623:24;;22692:2;22681:9;22677:18;22664:31;;22538:4;22535:1;22531:12;22526:17;;22501:208;;;22737:6;22728:7;22725:19;22722:179;;;22795:9;22790:3;22786:19;22780:26;22838:48;22880:4;22872:6;22868:17;22857:9;22838:48;:::i;:::-;22830:6;22823:64;22745:156;22722:179;22947:1;22943;22935:6;22931:14;22927:22;22921:4;22914:36;22349:611;;;22312:887;;21902:1303;;;21810:1395;;:::o;23211:191::-;23251:3;23270:20;23288:1;23270:20;:::i;:::-;23265:25;;23304:20;23322:1;23304:20;:::i;:::-;23299:25;;23347:1;23344;23340:9;23333:16;;23368:3;23365:1;23362:10;23359:36;;;23375:18;;:::i;:::-;23359:36;23211:191;;;;:::o;23408:194::-;23448:4;23468:20;23486:1;23468:20;:::i;:::-;23463:25;;23502:20;23520:1;23502:20;:::i;:::-;23497:25;;23546:1;23543;23539:9;23531:17;;23570:1;23564:4;23561:11;23558:37;;;23575:18;;:::i;:::-;23558:37;23408:194;;;;:::o;23608:180::-;23656:77;23653:1;23646:88;23753:4;23750:1;23743:15;23777:4;23774:1;23767:15;23794:185;23834:1;23851:20;23869:1;23851:20;:::i;:::-;23846:25;;23885:20;23903:1;23885:20;:::i;:::-;23880:25;;23924:1;23914:35;;23929:18;;:::i;:::-;23914:35;23971:1;23968;23964:9;23959:14;;23794:185;;;;:::o;23985:332::-;24106:4;24144:2;24133:9;24129:18;24121:26;;24157:71;24225:1;24214:9;24210:17;24201:6;24157:71;:::i;:::-;24238:72;24306:2;24295:9;24291:18;24282:6;24238:72;:::i;:::-;23985:332;;;;;:::o;24323:137::-;24377:5;24408:6;24402:13;24393:22;;24424:30;24448:5;24424:30;:::i;:::-;24323:137;;;;:::o;24466:345::-;24533:6;24582:2;24570:9;24561:7;24557:23;24553:32;24550:119;;;24588:79;;:::i;:::-;24550:119;24708:1;24733:61;24786:7;24777:6;24766:9;24762:22;24733:61;:::i;:::-;24723:71;;24679:125;24466:345;;;;:::o;24817:174::-;24957:26;24953:1;24945:6;24941:14;24934:50;24817:174;:::o;24997:366::-;25139:3;25160:67;25224:2;25219:3;25160:67;:::i;:::-;25153:74;;25236:93;25325:3;25236:93;:::i;:::-;25354:2;25349:3;25345:12;25338:19;;24997:366;;;:::o;25369:419::-;25535:4;25573:2;25562:9;25558:18;25550:26;;25622:9;25616:4;25612:20;25608:1;25597:9;25593:17;25586:47;25650:131;25776:4;25650:131;:::i;:::-;25642:139;;25369:419;;;:::o;25794:228::-;25934:34;25930:1;25922:6;25918:14;25911:58;26003:11;25998:2;25990:6;25986:15;25979:36;25794:228;:::o;26028:366::-;26170:3;26191:67;26255:2;26250:3;26191:67;:::i;:::-;26184:74;;26267:93;26356:3;26267:93;:::i;:::-;26385:2;26380:3;26376:12;26369:19;;26028:366;;;:::o;26400:419::-;26566:4;26604:2;26593:9;26589:18;26581:26;;26653:9;26647:4;26643:20;26639:1;26628:9;26624:17;26617:47;26681:131;26807:4;26681:131;:::i;:::-;26673:139;;26400:419;;;:::o;26825:232::-;26965:34;26961:1;26953:6;26949:14;26942:58;27034:15;27029:2;27021:6;27017:15;27010:40;26825:232;:::o;27063:366::-;27205:3;27226:67;27290:2;27285:3;27226:67;:::i;:::-;27219:74;;27302:93;27391:3;27302:93;:::i;:::-;27420:2;27415:3;27411:12;27404:19;;27063:366;;;:::o;27435:419::-;27601:4;27639:2;27628:9;27624:18;27616:26;;27688:9;27682:4;27678:20;27674:1;27663:9;27659:17;27652:47;27716:131;27842:4;27716:131;:::i;:::-;27708:139;;27435:419;;;:::o;27860:148::-;27962:11;27999:3;27984:18;;27860:148;;;;:::o;28014:390::-;28120:3;28148:39;28181:5;28148:39;:::i;:::-;28203:89;28285:6;28280:3;28203:89;:::i;:::-;28196:96;;28301:65;28359:6;28354:3;28347:4;28340:5;28336:16;28301:65;:::i;:::-;28391:6;28386:3;28382:16;28375:23;;28124:280;28014:390;;;;:::o;28410:595::-;28638:3;28660:95;28751:3;28742:6;28660:95;:::i;:::-;28653:102;;28772:95;28863:3;28854:6;28772:95;:::i;:::-;28765:102;;28884:95;28975:3;28966:6;28884:95;:::i;:::-;28877:102;;28996:3;28989:10;;28410:595;;;;;;:::o;29011:332::-;29132:4;29170:2;29159:9;29155:18;29147:26;;29183:71;29251:1;29240:9;29236:17;29227:6;29183:71;:::i;:::-;29264:72;29332:2;29321:9;29317:18;29308:6;29264:72;:::i;:::-;29011:332;;;;;:::o;29349:220::-;29489:34;29485:1;29477:6;29473:14;29466:58;29558:3;29553:2;29545:6;29541:15;29534:28;29349:220;:::o;29575:366::-;29717:3;29738:67;29802:2;29797:3;29738:67;:::i;:::-;29731:74;;29814:93;29903:3;29814:93;:::i;:::-;29932:2;29927:3;29923:12;29916:19;;29575:366;;;:::o;29947:419::-;30113:4;30151:2;30140:9;30136:18;30128:26;;30200:9;30194:4;30190:20;30186:1;30175:9;30171:17;30164:47;30228:131;30354:4;30228:131;:::i;:::-;30220:139;;29947:419;;;:::o;30372:248::-;30512:34;30508:1;30500:6;30496:14;30489:58;30581:31;30576:2;30568:6;30564:15;30557:56;30372:248;:::o;30626:366::-;30768:3;30789:67;30853:2;30848:3;30789:67;:::i;:::-;30782:74;;30865:93;30954:3;30865:93;:::i;:::-;30983:2;30978:3;30974:12;30967:19;;30626:366;;;:::o;30998:419::-;31164:4;31202:2;31191:9;31187:18;31179:26;;31251:9;31245:4;31241:20;31237:1;31226:9;31222:17;31215:47;31279:131;31405:4;31279:131;:::i;:::-;31271:139;;30998:419;;;:::o;31423:237::-;31563:34;31559:1;31551:6;31547:14;31540:58;31632:20;31627:2;31619:6;31615:15;31608:45;31423:237;:::o;31666:366::-;31808:3;31829:67;31893:2;31888:3;31829:67;:::i;:::-;31822:74;;31905:93;31994:3;31905:93;:::i;:::-;32023:2;32018:3;32014:12;32007:19;;31666:366;;;:::o;32038:419::-;32204:4;32242:2;32231:9;32227:18;32219:26;;32291:9;32285:4;32281:20;32277:1;32266:9;32262:17;32255:47;32319:131;32445:4;32319:131;:::i;:::-;32311:139;;32038:419;;;:::o;32463:224::-;32603:34;32599:1;32591:6;32587:14;32580:58;32672:7;32667:2;32659:6;32655:15;32648:32;32463:224;:::o;32693:366::-;32835:3;32856:67;32920:2;32915:3;32856:67;:::i;:::-;32849:74;;32932:93;33021:3;32932:93;:::i;:::-;33050:2;33045:3;33041:12;33034:19;;32693:366;;;:::o;33065:419::-;33231:4;33269:2;33258:9;33254:18;33246:26;;33318:9;33312:4;33308:20;33304:1;33293:9;33289:17;33282:47;33346:131;33472:4;33346:131;:::i;:::-;33338:139;;33065:419;;;:::o;33490:223::-;33630:34;33626:1;33618:6;33614:14;33607:58;33699:6;33694:2;33686:6;33682:15;33675:31;33490:223;:::o;33719:366::-;33861:3;33882:67;33946:2;33941:3;33882:67;:::i;:::-;33875:74;;33958:93;34047:3;33958:93;:::i;:::-;34076:2;34071:3;34067:12;34060:19;;33719:366;;;:::o;34091:419::-;34257:4;34295:2;34284:9;34280:18;34272:26;;34344:9;34338:4;34334:20;34330:1;34319:9;34315:17;34308:47;34372:131;34498:4;34372:131;:::i;:::-;34364:139;;34091:419;;;:::o;34516:175::-;34656:27;34652:1;34644:6;34640:14;34633:51;34516:175;:::o;34697:366::-;34839:3;34860:67;34924:2;34919:3;34860:67;:::i;:::-;34853:74;;34936:93;35025:3;34936:93;:::i;:::-;35054:2;35049:3;35045:12;35038:19;;34697:366;;;:::o;35069:419::-;35235:4;35273:2;35262:9;35258:18;35250:26;;35322:9;35316:4;35312:20;35308:1;35297:9;35293:17;35286:47;35350:131;35476:4;35350:131;:::i;:::-;35342:139;;35069:419;;;:::o;35494:98::-;35545:6;35579:5;35573:12;35563:22;;35494:98;;;:::o;35598:168::-;35681:11;35715:6;35710:3;35703:19;35755:4;35750:3;35746:14;35731:29;;35598:168;;;;:::o;35772:373::-;35858:3;35886:38;35918:5;35886:38;:::i;:::-;35940:70;36003:6;35998:3;35940:70;:::i;:::-;35933:77;;36019:65;36077:6;36072:3;36065:4;36058:5;36054:16;36019:65;:::i;:::-;36109:29;36131:6;36109:29;:::i;:::-;36104:3;36100:39;36093:46;;35862:283;35772:373;;;;:::o;36151:640::-;36346:4;36384:3;36373:9;36369:19;36361:27;;36398:71;36466:1;36455:9;36451:17;36442:6;36398:71;:::i;:::-;36479:72;36547:2;36536:9;36532:18;36523:6;36479:72;:::i;:::-;36561;36629:2;36618:9;36614:18;36605:6;36561:72;:::i;:::-;36680:9;36674:4;36670:20;36665:2;36654:9;36650:18;36643:48;36708:76;36779:4;36770:6;36708:76;:::i;:::-;36700:84;;36151:640;;;;;;;:::o;36797:141::-;36853:5;36884:6;36878:13;36869:22;;36900:32;36926:5;36900:32;:::i;:::-;36797:141;;;;:::o;36944:349::-;37013:6;37062:2;37050:9;37041:7;37037:23;37033:32;37030:119;;;37068:79;;:::i;:::-;37030:119;37188:1;37213:63;37268:7;37259:6;37248:9;37244:22;37213:63;:::i;:::-;37203:73;;37159:127;36944:349;;;;:::o;37299:182::-;37439:34;37435:1;37427:6;37423:14;37416:58;37299:182;:::o;37487:366::-;37629:3;37650:67;37714:2;37709:3;37650:67;:::i;:::-;37643:74;;37726:93;37815:3;37726:93;:::i;:::-;37844:2;37839:3;37835:12;37828:19;;37487:366;;;:::o;37859:419::-;38025:4;38063:2;38052:9;38048:18;38040:26;;38112:9;38106:4;38102:20;38098:1;38087:9;38083:17;38076:47;38140:131;38266:4;38140:131;:::i;:::-;38132:139;;37859:419;;;:::o;38284:178::-;38424:30;38420:1;38412:6;38408:14;38401:54;38284:178;:::o;38468:366::-;38610:3;38631:67;38695:2;38690:3;38631:67;:::i;:::-;38624:74;;38707:93;38796:3;38707:93;:::i;:::-;38825:2;38820:3;38816:12;38809:19;;38468:366;;;:::o;38840:419::-;39006:4;39044:2;39033:9;39029:18;39021:26;;39093:9;39087:4;39083:20;39079:1;39068:9;39064:17;39057:47;39121:131;39247:4;39121:131;:::i;:::-;39113:139;;38840:419;;;:::o;39265:240::-;39405:34;39401:1;39393:6;39389:14;39382:58;39474:23;39469:2;39461:6;39457:15;39450:48;39265:240;:::o;39511:366::-;39653:3;39674:67;39738:2;39733:3;39674:67;:::i;:::-;39667:74;;39750:93;39839:3;39750:93;:::i;:::-;39868:2;39863:3;39859:12;39852:19;;39511:366;;;:::o;39883:419::-;40049:4;40087:2;40076:9;40072:18;40064:26;;40136:9;40130:4;40126:20;40122:1;40111:9;40107:17;40100:47;40164:131;40290:4;40164:131;:::i;:::-;40156:139;;39883:419;;;:::o;40308:180::-;40356:77;40353:1;40346:88;40453:4;40450:1;40443:15;40477:4;40474:1;40467:15

Swarm Source

ipfs://b33bbdf69fe3fc3dffa8908864c177301ae8d1fb98204f8b3567fee043a3db27
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.