ETH Price: $2,319.06 (-2.43%)
 

Overview

Max Total Supply

100,000,000 DEEPR

Holders

710

Transfers

-
0

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

-

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
DeeprTemplate

Compiler Version
v0.8.30+commit.73712a01

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, GNU GPLv2 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at basescan.org on 2025-05-29
*/

// SPDX-License-Identifier: GPL-2.0-or-later

//    ___  ___________  ___    ______  ___  __
//   / _ \/ __/ __/ _ \/ _ \  / __/ / / / |/ /
//  / // / _// _// ___/ , _/ / _// /_/ /    / 
// /____/___/___/_/  /_/|_(_)_/  \____/_/|_/    
//
// This contract was deployed using the DEEPR.FUN Progressive Liquidity Launchpad, 
// designed with fairer tokenomics and transparent distribution to all market participants.
//
// https://deepr.fun
// https://x.com/deeprfun
// https://t.me/deeprfunportal


// File: @openzeppelin/contracts/token/ERC20/IERC20.sol


// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol


// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;


/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

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


// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// File: @openzeppelin/contracts/interfaces/draft-IERC6093.sol


// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC-20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC-721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC-1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

// File: @openzeppelin/contracts/token/ERC20/ERC20.sol


// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;





/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC-20
 * applications.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * Both values are immutable: they can only be set once during construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

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

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

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

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Skips emitting an {Approval} event indicating an allowance update. This is not
     * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     *
     * ```solidity
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner`'s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance < type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

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


// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

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


// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)

pragma solidity ^0.8.20;

/**
 * @dev Helper library for emitting standardized panic codes.
 *
 * ```solidity
 * contract Example {
 *      using Panic for uint256;
 *
 *      // Use any of the declared internal constants
 *      function foo() { Panic.GENERIC.panic(); }
 *
 *      // Alternatively
 *      function foo() { Panic.panic(Panic.GENERIC); }
 * }
 * ```
 *
 * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
 *
 * _Available since v5.1._
 */
// slither-disable-next-line unused-state
library Panic {
    /// @dev generic / unspecified error
    uint256 internal constant GENERIC = 0x00;
    /// @dev used by the assert() builtin
    uint256 internal constant ASSERT = 0x01;
    /// @dev arithmetic underflow or overflow
    uint256 internal constant UNDER_OVERFLOW = 0x11;
    /// @dev division or modulo by zero
    uint256 internal constant DIVISION_BY_ZERO = 0x12;
    /// @dev enum conversion error
    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
    /// @dev invalid encoding in storage
    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
    /// @dev empty array pop
    uint256 internal constant EMPTY_ARRAY_POP = 0x31;
    /// @dev array out of bounds access
    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
    /// @dev resource error (too large allocation or too large array)
    uint256 internal constant RESOURCE_ERROR = 0x41;
    /// @dev calling invalid internal function
    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;

    /// @dev Reverts with a panic code. Recommended to use with
    /// the internal constants with predefined codes.
    function panic(uint256 code) internal pure {
        assembly ("memory-safe") {
            mstore(0x00, 0x4e487b71)
            mstore(0x20, code)
            revert(0x1c, 0x24)
        }
    }
}

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


// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}

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


// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;



/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Return the 512-bit addition of two uint256.
     *
     * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
     */
    function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        assembly ("memory-safe") {
            low := add(a, b)
            high := lt(low, a)
        }
    }

    /**
     * @dev Return the 512-bit multiplication of two uint256.
     *
     * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
     */
    function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
        // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = high * 2²⁵⁶ + low.
        assembly ("memory-safe") {
            let mm := mulmod(a, b, not(0))
            low := mul(a, b)
            high := sub(sub(mm, low), lt(mm, low))
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a + b;
            success = c >= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a - b;
            success = c <= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a * b;
            assembly ("memory-safe") {
                // Only true when the multiplication doesn't overflow
                // (c / a == b) || (a == 0)
                success := or(eq(div(c, a), b), iszero(a))
            }
            // equivalent to: success ? c : 0
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `DIV` opcode returns zero when the denominator is 0.
                result := div(a, b)
            }
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `MOD` opcode returns zero when the denominator is 0.
                result := mod(a, b)
            }
        }
    }

    /**
     * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryAdd(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
     */
    function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
        (, uint256 result) = trySub(a, b);
        return result;
    }

    /**
     * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryMul(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
     *
     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
     * one branch when needed, making this function more expensive.
     */
    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * SafeCast.toUint(condition));
        }
    }

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

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(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 towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        // The following calculation ensures accurate ceiling division without overflow.
        // Since a is non-zero, (a - 1) / b will not overflow.
        // The largest possible result occurs when (a - 1) / b is type(uint256).max,
        // but the largest value we can obtain is type(uint256).max - 1, which happens
        // when a = type(uint256).max and b = 1.
        unchecked {
            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
        }
    }

    /**
     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     *
     * 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 {
            (uint256 high, uint256 low) = mul512(x, y);

            // Handle non-overflow cases, 256 by 256 division.
            if (high == 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 low / denominator;
            }

            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
            if (denominator <= high) {
                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
            }

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

            // Make division exact by subtracting the remainder from [high low].
            uint256 remainder;
            assembly ("memory-safe") {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                high := sub(high, gt(remainder, low))
                low := sub(low, 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.

            uint256 twos = denominator & (0 - denominator);
            assembly ("memory-safe") {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [high low] by twos.
                low := div(low, twos)

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

            // Shift in bits from high into low.
            low |= high * twos;

            // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.
            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⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
            inverse *= 2 - denominator * inverse; // inverse mod 2³²
            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶

            // 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²⁵⁶. Since the preconditions guarantee that the outcome is
            // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
            // is no longer required.
            result = low * inverse;
            return result;
        }
    }

    /**
     * @dev 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) {
        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
    }

    /**
     * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
     */
    function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);
            if (high >= 1 << n) {
                Panic.panic(Panic.UNDER_OVERFLOW);
            }
            return (high << (256 - n)) | (low >> n);
        }
    }

    /**
     * @dev Calculates x * y >> n with full precision, following the selected rounding direction.
     */
    function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
        return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
    }

    /**
     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
     *
     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
     *
     * If the input value is not inversible, 0 is returned.
     *
     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
     */
    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
        unchecked {
            if (n == 0) return 0;

            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
            // Used to compute integers x and y such that: ax + ny = gcd(a, n).
            // When the gcd is 1, then the inverse of a modulo n exists and it's x.
            // ax + ny = 1
            // ax = 1 + (-y)n
            // ax ≡ 1 (mod n) # x is the inverse of a modulo n

            // If the remainder is 0 the gcd is n right away.
            uint256 remainder = a % n;
            uint256 gcd = n;

            // Therefore the initial coefficients are:
            // ax + ny = gcd(a, n) = n
            // 0a + 1n = n
            int256 x = 0;
            int256 y = 1;

            while (remainder != 0) {
                uint256 quotient = gcd / remainder;

                (gcd, remainder) = (
                    // The old remainder is the next gcd to try.
                    remainder,
                    // Compute the next remainder.
                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
                    // where gcd is at most n (capped to type(uint256).max)
                    gcd - remainder * quotient
                );

                (x, y) = (
                    // Increment the coefficient of a.
                    y,
                    // Decrement the coefficient of n.
                    // Can overflow, but the result is casted to uint256 so that the
                    // next value of y is "wrapped around" to a value between 0 and n - 1.
                    x - y * int256(quotient)
                );
            }

            if (gcd != 1) return 0; // No inverse exists.
            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
        }
    }

    /**
     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
     *
     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.
     *
     * NOTE: this function does NOT check that `p` is a prime greater than `2`.
     */
    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
        unchecked {
            return Math.modExp(a, p - 2, p);
        }
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
     *
     * Requirements:
     * - modulus can't be zero
     * - underlying staticcall to precompile must succeed
     *
     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
     * sure the chain you're using it on supports the precompiled contract for modular exponentiation
     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly
     * interpreted as 0.
     */
    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
        (bool success, uint256 result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
     * to operate modulo 0 or if the underlying precompile reverted.
     *
     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
     * of a revert, but the result may be incorrectly interpreted as 0.
     */
    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
        if (m == 0) return (false, 0);
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            // | Offset    | Content    | Content (Hex)                                                      |
            // |-----------|------------|--------------------------------------------------------------------|
            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x60:0x7f | value of b | 0x<.............................................................b> |
            // | 0x80:0x9f | value of e | 0x<.............................................................e> |
            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |
            mstore(ptr, 0x20)
            mstore(add(ptr, 0x20), 0x20)
            mstore(add(ptr, 0x40), 0x20)
            mstore(add(ptr, 0x60), b)
            mstore(add(ptr, 0x80), e)
            mstore(add(ptr, 0xa0), m)

            // Given the result < m, it's guaranteed to fit in 32 bytes,
            // so we can use the memory scratch space located at offset 0.
            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
            result := mload(0x00)
        }
    }

    /**
     * @dev Variant of {modExp} that supports inputs of arbitrary length.
     */
    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
        (bool success, bytes memory result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.
     */
    function tryModExp(
        bytes memory b,
        bytes memory e,
        bytes memory m
    ) internal view returns (bool success, bytes memory result) {
        if (_zeroBytes(m)) return (false, new bytes(0));

        uint256 mLen = m.length;

        // Encode call args in result and move the free memory pointer
        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);

        assembly ("memory-safe") {
            let dataPtr := add(result, 0x20)
            // Write result on top of args to avoid allocating extra memory.
            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
            // Overwrite the length.
            // result.length > returndatasize() is guaranteed because returndatasize() == m.length
            mstore(result, mLen)
            // Set the memory pointer after the returned data.
            mstore(0x40, add(dataPtr, mLen))
        }
    }

    /**
     * @dev Returns whether the provided byte array is zero.
     */
    function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
        for (uint256 i = 0; i < byteArray.length; ++i) {
            if (byteArray[i] != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only
     * using integer operations.
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        unchecked {
            // Take care of easy edge cases when a == 0 or a == 1
            if (a <= 1) {
                return a;
            }

            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
            // the current value as `ε_n = | x_n - sqrt(a) |`.
            //
            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
            // bigger than any uint256.
            //
            // By noticing that
            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
            // to the msb function.
            uint256 aa = a;
            uint256 xn = 1;

            if (aa >= (1 << 128)) {
                aa >>= 128;
                xn <<= 64;
            }
            if (aa >= (1 << 64)) {
                aa >>= 64;
                xn <<= 32;
            }
            if (aa >= (1 << 32)) {
                aa >>= 32;
                xn <<= 16;
            }
            if (aa >= (1 << 16)) {
                aa >>= 16;
                xn <<= 8;
            }
            if (aa >= (1 << 8)) {
                aa >>= 8;
                xn <<= 4;
            }
            if (aa >= (1 << 4)) {
                aa >>= 4;
                xn <<= 2;
            }
            if (aa >= (1 << 2)) {
                xn <<= 1;
            }

            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
            //
            // We can refine our estimation by noticing that the middle of that interval minimizes the error.
            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
            // This is going to be our x_0 (and ε_0)
            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)

            // From here, Newton's method give us:
            // x_{n+1} = (x_n + a / x_n) / 2
            //
            // One should note that:
            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
            //              = ((x_n² + a) / (2 * x_n))² - a
            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
            //              = (x_n² - a)² / (2 * x_n)²
            //              = ((x_n² - a) / (2 * x_n))²
            //              ≥ 0
            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
            //
            // This gives us the proof of quadratic convergence of the sequence:
            // ε_{n+1} = | x_{n+1} - sqrt(a) |
            //         = | (x_n + a / x_n) / 2 - sqrt(a) |
            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
            //         = | (x_n - sqrt(a))² / (2 * x_n) |
            //         = | ε_n² / (2 * x_n) |
            //         = ε_n² / | (2 * x_n) |
            //
            // For the first iteration, we have a special case where x_0 is known:
            // ε_1 = ε_0² / | (2 * x_0) |
            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))
            //     ≤ 2**(e-3) / 3
            //     ≤ 2**(e-3-log2(3))
            //     ≤ 2**(e-4.5)
            //
            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
            // ε_{n+1} = ε_n² / | (2 * x_n) |
            //         ≤ (2**(e-k))² / (2 * 2**(e-1))
            //         ≤ 2**(2*e-2*k) / 2**e
            //         ≤ 2**(e-2*k)
            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above
            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5
            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9
            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18
            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36
            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72

            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
            // sqrt(a) or sqrt(a) + 1.
            return xn - SafeCast.toUint(xn > a / xn);
        }
    }

    /**
     * @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // If upper 8 bits of 16-bit half set, add 8 to result
        r |= SafeCast.toUint((x >> r) > 0xff) << 3;
        // If upper 4 bits of 8-bit half set, add 4 to result
        r |= SafeCast.toUint((x >> r) > 0xf) << 2;

        // Shifts value right by the current result and use it as an index into this lookup table:
        //
        // | x (4 bits) |  index  | table[index] = MSB position |
        // |------------|---------|-----------------------------|
        // |    0000    |    0    |        table[0] = 0         |
        // |    0001    |    1    |        table[1] = 0         |
        // |    0010    |    2    |        table[2] = 1         |
        // |    0011    |    3    |        table[3] = 1         |
        // |    0100    |    4    |        table[4] = 2         |
        // |    0101    |    5    |        table[5] = 2         |
        // |    0110    |    6    |        table[6] = 2         |
        // |    0111    |    7    |        table[7] = 2         |
        // |    1000    |    8    |        table[8] = 3         |
        // |    1001    |    9    |        table[9] = 3         |
        // |    1010    |   10    |        table[10] = 3        |
        // |    1011    |   11    |        table[11] = 3        |
        // |    1100    |   12    |        table[12] = 3        |
        // |    1101    |   13    |        table[13] = 3        |
        // |    1110    |   14    |        table[14] = 3        |
        // |    1111    |   15    |        table[15] = 3        |
        //
        // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
        assembly ("memory-safe") {
            r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
        }
    }

    /**
     * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * 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 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
        return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
    }

    /**
     * @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// File: @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol

pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

// File: @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol

pragma solidity >=0.6.2;


interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

// File: @uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol

pragma solidity >=0.5.0;

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

// File: @uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol

pragma solidity >=0.5.0;

interface IUniswapV2Factory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint) external view returns (address pair);
    function allPairsLength() external view returns (uint);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}

// File: template.sol


pragma solidity ^0.8.28;








contract DeeprTemplate is ERC20, ReentrancyGuard {
    IUniswapV2Router02 public uniswapV2Router;
    IUniswapV2Pair public uniswapV2Pair;

    address public immutable deployer; // Store deployer address
    address public immutable DEEPR_VAULT = 0x4F8411a4Ff4E9Ad6905612009CDcB8367602b4Fc;
    address public immutable DEEPR_AIRDROP = 0xF08B1fE0Cf1210F83a5f8C026c0Fd4f717D195FE;
    uint256 public trancheFee = 1000; // 10% fee on LP creation (10% ETH raised, 5% token supply)

    uint256 public initialPricePerToken;
    uint256[14] public priceMultiples = [1, 5, 10, 20, 40, 80, 160, 320, 640, 1280, 2560, 5120, 10240, 20480];
    uint256[14] public trancheRelease = [2200, 880, 590, 390, 270, 190, 140, 100, 60, 50, 40, 40, 30, 20];
    uint256[14] public trancheMaxPurchase;
    uint256[14] public trancheSupply;
    uint256[14] public trancheSold;
    
    bool public initialLiquidityDeployed = false;

    // Track contributors
    address[] public initialContributors;
    mapping(address => bool) public isInitialContributor;
    mapping(address => uint256[14]) public userTranchePurchases;
    mapping(address => uint256[14]) public userTrancheETHPaid;

    // Custom Events
    event InitialTranchePurchase(address indexed buyer, uint256 amount);
    event TrancheTokensPurchased(address indexed buyer, uint256 trancheIndex, uint256 amount);
    event InitialTrancheRefunded(address indexed buyer, uint256 amount);
    event TrancheCompleted(uint256 indexed trancheIndex, uint256 totalSold, uint256 blockNumber);
    event ExcessETHRefunded(address indexed buyer, uint256 refundAmount, uint256 ethSent, uint256 ethUsed);

    // Custom errors
    error LiquidityDeployed();
    error LiquidityNotDeployed();
    error ZeroETHSent();
    error InvalidTrancheIndex();
    error InvalidPriceDifference();
    error TranchePriceExceedsMarket();
    error PriceOutsideRange();
    error TrancheSoldOut();
    error InsufficientTokenBalance();
    error InsufficientETHBalance();
    error WalletLimitReached();
    error NoRefundAvailable();
    error InitialSaleEnded();
    error MaxPriorityFeeExceeded();

    uint256 public maxPriorityFee = 3 * 1e9; //3 gwei

    modifier checkPriorityFee() {
        if ((tx.gasprice - block.basefee) > maxPriorityFee) revert MaxPriorityFeeExceeded();
        _;
    }

    /// @notice Contract constructor
    /// @param uniswapV2Router_ Address of the Uniswap V2 Router
    /// @param totalSupply_ Total supply of the token
    /// @param ethRaiseinWei_ Target ETH raise amount in Wei for the initial tranche
    /// @param name_ Name of the ERC20 token
    /// @param symbol_ Symbol of the ERC20 token
    /// @dev Initializes ERC20, sets up tranche supplies and purchase limits, calculates initial price, creates Uniswap pair, mints total supply to the contract, and sets the deployer address.
    constructor(address uniswapV2Router_, uint256 totalSupply_, uint256 ethRaiseinWei_, string memory name_, string memory symbol_) 
        payable ERC20(name_, symbol_) 
    {   
        deployer = msg.sender; // Set deployer on construction
        trancheSupply[0] = (totalSupply_ / 10000) * trancheRelease[0];
        trancheSupply[1] = (totalSupply_ / 10000) * trancheRelease[1];
        trancheSupply[2] = (totalSupply_ / 10000) * trancheRelease[2];
        trancheSupply[3] = (totalSupply_ / 10000) * trancheRelease[3];
        trancheSupply[4] = (totalSupply_ / 10000) * trancheRelease[4];
        trancheSupply[5] = (totalSupply_ / 10000) * trancheRelease[5];
        trancheSupply[6] = (totalSupply_ / 10000) * trancheRelease[6];
        trancheSupply[7] = (totalSupply_ / 10000) * trancheRelease[7];
        trancheSupply[8] = (totalSupply_ / 10000) * trancheRelease[8];
        trancheSupply[9] = (totalSupply_ / 10000) * trancheRelease[9];
        trancheSupply[10] = (totalSupply_ / 10000) * trancheRelease[10];
        trancheSupply[11] = (totalSupply_ / 10000) * trancheRelease[11];
        trancheSupply[12] = (totalSupply_ / 10000) * trancheRelease[12];
        trancheSupply[13] = (totalSupply_ / 10000) * trancheRelease[13];

        trancheMaxPurchase[0] = trancheSupply[0] * 9900 / 10000;
        trancheMaxPurchase[1] = trancheSupply[1] * 500 / 10000;
        trancheMaxPurchase[2] = trancheSupply[2] * 500 / 10000;
        trancheMaxPurchase[3] = trancheSupply[3] * 1000 / 10000;
        trancheMaxPurchase[4] = trancheSupply[4] * 1000 / 10000;
        trancheMaxPurchase[5] = trancheSupply[5] * 1000 / 10000;
        trancheMaxPurchase[6] = trancheSupply[6] * 2000 / 10000;
        trancheMaxPurchase[7] = trancheSupply[7] * 2000 / 10000;
        trancheMaxPurchase[8] = trancheSupply[8] * 2000 / 10000;
        trancheMaxPurchase[9] = trancheSupply[9];
        trancheMaxPurchase[10] = trancheSupply[10];
        trancheMaxPurchase[11] = trancheSupply[11];
        trancheMaxPurchase[12] = trancheSupply[12];
        trancheMaxPurchase[13] = trancheSupply[13];

        uniswapV2Router = IUniswapV2Router02(uniswapV2Router_);
        uniswapV2Pair = IUniswapV2Pair(IUniswapV2Factory(uniswapV2Router.factory()).createPair(address(this), uniswapV2Router.WETH()));

        initialPricePerToken = (ethRaiseinWei_ * 1e18) / trancheSupply[0];
        
        _mint(address(this), totalSupply_);

        if (msg.value > 0) {
            // Validate ETH sent (mimic buyInitialTranche validation)
            if (trancheSold[0] >= trancheSupply[0]) revert TrancheSoldOut();
            if (userTranchePurchases[msg.sender][0] >= trancheMaxPurchase[0]) revert WalletLimitReached();

            // Calculate maximum tokens user can buy (same logic as buyInitialTranche)
            uint256 tokensToBuy = _calculatePurchaseAmount(0, msg.value, initialPricePerToken);
            uint256 cost = (tokensToBuy * initialPricePerToken) / 1e18;

            // Add to contributors array if first purchase (same logic as buyInitialTranche)
            if (!isInitialContributor[msg.sender]) {
                initialContributors.push(msg.sender);
                isInitialContributor[msg.sender] = true;
            }

            // Update state (same logic as buyInitialTranche - use += not =)
            trancheSold[0] += tokensToBuy;
            userTranchePurchases[msg.sender][0] += tokensToBuy;
            userTrancheETHPaid[msg.sender][0] += cost;

            // Refund excess ETH before any distributions or liquidity deployment
            if (msg.value > cost) {
                uint256 refundAmount = msg.value - cost;
                payable(msg.sender).transfer(refundAmount);
                emit ExcessETHRefunded(msg.sender, refundAmount, msg.value, cost);
            }

            // Emit purchase event (same as buyInitialTranche)
            emit InitialTranchePurchase(msg.sender, tokensToBuy);
        }
    }

    // Function to allow the contract to receive ETH
    receive() external payable {}

    /// @notice Purchase tokens from the initial tranche (tranche 0)
    /// @dev Allows purchase up to the wallet limit (`trancheMaxPurchase[0]`), distributes tokens and deploys initial liquidity (calling `_handleFeesAndLiquidity`) when sold out.
    /// @dev Tokens are held by the contract until the tranche is fully sold. Excess ETH is refunded immediately.
    function buyInitialTranche() external payable nonReentrant checkPriorityFee {
        if (initialLiquidityDeployed) revert LiquidityDeployed();
        if (msg.value == 0) revert ZeroETHSent();
        if (trancheSold[0] >= trancheSupply[0]) revert TrancheSoldOut();
        if (userTranchePurchases[msg.sender][0] >= trancheMaxPurchase[0]) revert WalletLimitReached();

        // Calculate maximum tokens user can buy
        uint256 tokensToBuy = _calculatePurchaseAmount(0, msg.value, initialPricePerToken);
        uint256 cost = (tokensToBuy * initialPricePerToken) / 1e18;
        userTrancheETHPaid[msg.sender][0] += cost;

        // Add to contributors array if first purchase
        if (!isInitialContributor[msg.sender]) {
            initialContributors.push(msg.sender);
            isInitialContributor[msg.sender] = true;
        }

        // Update state (but don't transfer tokens yet)
        trancheSold[0] += tokensToBuy;
        userTranchePurchases[msg.sender][0] += tokensToBuy;

        // Refund excess ETH before any distributions or liquidity deployment
        if (msg.value > cost) {
            uint256 refundAmount = msg.value - cost;
            payable(msg.sender).transfer(refundAmount);
            emit ExcessETHRefunded(msg.sender, refundAmount, msg.value, cost);
        }
        
        // Check if tranche is fully sold
        if (trancheSold[0] >= trancheSupply[0]) {
            _distributeInitialTokens();
            _deployInitialLiquidity();
        }
        
        if (trancheSold[0] >= trancheSupply[0]) {
            emit TrancheCompleted(0, trancheSold[0], block.number);
        }

        emit InitialTranchePurchase(msg.sender, tokensToBuy);
    }

    /// @notice Distributes tokens to all initial tranche contributors
    /// @dev Iterates through `initialContributors` and transfers their purchased tokens from the contract. Resets their purchased amount for tranche 0.
    function _distributeInitialTokens() internal {

        // Distribute tokens to all contributors
        for (uint256 i = 0; i < initialContributors.length; ) {
            address contributor = initialContributors[i];
            uint256 amount = userTranchePurchases[contributor][0];
            if (amount > 0) {
                _transfer(address(this), contributor, amount);
                userTranchePurchases[contributor][0] = 0;
            }
            unchecked { ++i; }
        }
    }

    /// @notice Deploys initial liquidity to Uniswap with the collected ETH
    /// @dev Calculates ETH and tokens for liquidity based on `trancheSupply[0]` and contract's ETH balance, then calls `_handleFeesAndLiquidity` to handle fee distribution and add liquidity. Sets `initialLiquidityDeployed` to true.
    function _deployInitialLiquidity() internal {
        if (address(this).balance == 0) revert InsufficientETHBalance();

        uint256 ethForLiquidity = address(this).balance;
        uint256 tokensForLiquidity = trancheSupply[0];

        _handleFeesAndLiquidity(tokensForLiquidity, ethForLiquidity);
        
        initialLiquidityDeployed = true;
    }

    /// @notice Allows users to refund their initial tranche purchase
    /// @dev Only available during initial tranche sale period
    function refundInitialTranche() external nonReentrant {
        if (initialLiquidityDeployed) revert LiquidityDeployed();
        
        uint256 refundAmount = userTranchePurchases[msg.sender][0];
        if (refundAmount == 0) revert NoRefundAvailable();

        uint256 ethToRefund = userTrancheETHPaid[msg.sender][0];
        userTranchePurchases[msg.sender][0] = 0;
        userTrancheETHPaid[msg.sender][0] = 0;
        trancheSold[0] -= refundAmount;

        // Remove from contributors if this was their only purchase
        if (isInitialContributor[msg.sender]) {
            isInitialContributor[msg.sender] = false;
            
            // Find and remove from contributors array
            for (uint256 i = 0; i < initialContributors.length; i++) {
                if (initialContributors[i] == msg.sender) {
                    // Move the last element to this position and pop
                    initialContributors[i] = initialContributors[initialContributors.length - 1];
                    initialContributors.pop();
                    break;
                }
            }
        }

        // Send ETH refund
        payable(msg.sender).transfer(ethToRefund);

        emit InitialTrancheRefunded(msg.sender, refundAmount);
    }

    /// @notice Buy tokens from a specific tranche and add liquidity
    /// @param trancheIndex The index of the tranche to buy from (1-13)
    /// @param maxPriceDifferencePercent Maximum acceptable positive price difference from tranche price in basis points (100 = 1%)
    /// @dev Purchases tokens if market price is within acceptable range of tranche price. Calls `_handleFeesAndLiquidity` to take the 10% fee (75% ETH to deployer, 25% ETH to vault, 100% tokens to airdrop) and add the rest to liquidity. Transfers purchased tokens to the buyer and refunds excess ETH.
    function buyTranche(uint256 trancheIndex, uint256 maxPriceDifferencePercent) external payable nonReentrant checkPriorityFee {
        if (!initialLiquidityDeployed) revert LiquidityNotDeployed();
        if (msg.value == 0) revert ZeroETHSent();
        if (trancheIndex == 0 || trancheIndex >= priceMultiples.length) revert InvalidTrancheIndex();
        if (maxPriceDifferencePercent < 100) revert InvalidPriceDifference();
        if (trancheSold[trancheIndex] >= trancheSupply[trancheIndex]) revert TrancheSoldOut();
        if (userTranchePurchases[msg.sender][trancheIndex] >= trancheMaxPurchase[trancheIndex]) revert WalletLimitReached();

        // Validate prices
        uint256 currentPrice = getTokenPriceInETH();
        uint256 tranchePrice = initialPricePerToken * priceMultiples[trancheIndex];
        if (currentPrice < tranchePrice) revert TranchePriceExceedsMarket();
        if (currentPrice > (tranchePrice + (tranchePrice * maxPriceDifferencePercent / 10000))) revert PriceOutsideRange();

        // Calculate purchase amount (combines multiple checks into one)
        uint256 tokensToBuy = _calculatePurchaseAmount(
            trancheIndex,
            msg.value,
            currentPrice
        );
        
        uint256 ethToUse = (tokensToBuy * currentPrice) / 1e18;
        if (balanceOf(address(this)) < tokensToBuy) revert InsufficientTokenBalance();

        // Handle fees and liquidity
        _handleFeesAndLiquidity(tokensToBuy, ethToUse);
        
        // Update state
        trancheSold[trancheIndex] += tokensToBuy;
        userTranchePurchases[msg.sender][trancheIndex] += tokensToBuy;
        userTrancheETHPaid[msg.sender][trancheIndex] += ethToUse;

        // Refund excess ETH
        if (msg.value > ethToUse) {
            uint256 refundAmount = msg.value - ethToUse;
            payable(msg.sender).transfer(refundAmount);
            emit ExcessETHRefunded(msg.sender, refundAmount, msg.value, ethToUse);
        }

        // Transfer tokens to buyer
        _transfer(address(this), msg.sender, tokensToBuy);

        if (trancheSold[trancheIndex] >= trancheSupply[trancheIndex]) {
            emit TrancheCompleted(trancheIndex, trancheSold[trancheIndex], block.number);
        }

        emit TrancheTokensPurchased(msg.sender, trancheIndex, tokensToBuy);
    }

    /// @notice Calculate the amount of tokens a user can purchase based on constraints
    /// @param trancheIndex The index of the tranche to buy from
    /// @param ethSent The amount of ETH sent for the purchase
    /// @param price The current price per token used for calculation
    /// @return The number of tokens that can be purchased, considering ETH sent, remaining tranche supply, and user's wallet limit for the tranche.
    function _calculatePurchaseAmount(
        uint256 trancheIndex,
        uint256 ethSent,
        uint256 price
    ) private view returns (uint256) {
        // Add check for price being 0 to prevent division by zero
        if (price == 0) return 0; 
        uint256 maxTokensForEth = (ethSent * 1e18) / price;
        uint256 remainingWalletLimit = trancheMaxPurchase[trancheIndex] - userTranchePurchases[msg.sender][trancheIndex];
        uint256 remainingTokens = trancheSupply[trancheIndex] - trancheSold[trancheIndex];
        
        return Math.min(Math.min(maxTokensForEth, remainingTokens), remainingWalletLimit);
    }

    /// @notice Handles the distribution of fees and adds remaining to liquidity
    /// @param tokensForLiquidity The gross amount of tokens intended for liquidity (before fees)
    /// @param ethForLiquidity The gross amount of ETH intended for liquidity (before fees)
    /// @dev Takes trancheFee (10%) fee. Sends 100% token fee to DEEPR_AIRDROP. Splits ETH fee: 75% to deployer, 25% to DEEPR_VAULT. Adds remaining tokens and ETH to the Uniswap pool. Requires approval for the router to spend tokens.
    function _handleFeesAndLiquidity(uint256 tokensForLiquidity, uint256 ethForLiquidity) private {
        // Calculate total fees based on the new trancheFee (10%)
        uint256 feeTokens = tokensForLiquidity * trancheFee / 10000;
        uint256 feeEth = ethForLiquidity * trancheFee / 10000;

        // Calculate ETH distribution for fees
        uint256 deployerEthShare = feeEth * 75 / 100; // 75% of the ETH fee to deployer
        uint256 vaultEthShare = feeEth - deployerEthShare; // Remaining 25% of ETH fee to DEEPR_VAULT

        // Calculate amounts remaining for liquidity after fees
        uint256 tokensToAdd = tokensForLiquidity - feeTokens;
        uint256 ethToAdd = ethForLiquidity - feeEth;

        // Calculate minimum amounts with 5% slippage tolerance
        uint256 minTokens = (tokensToAdd * 95) / 100;
        uint256 minETH = (ethToAdd * 95) / 100;

        // Approve router to spend tokens for liquidity
        _approve(address(this), address(uniswapV2Router), tokensToAdd);

        // Transfer fees
        if (deployerEthShare > 0) {
            payable(deployer).transfer(deployerEthShare);
        }
        if (vaultEthShare > 0) {
            payable(DEEPR_VAULT).transfer(vaultEthShare);
        }
        if (feeTokens > 0) {
            _transfer(address(this), DEEPR_AIRDROP, feeTokens); // 100% of token fee to Airdrop
        }

        // Add liquidity if amounts are valid
        if (tokensToAdd > 0 && ethToAdd > 0) {
            uniswapV2Router.addLiquidityETH{value: ethToAdd}(
                address(this),
                tokensToAdd,
                minTokens,
                minETH,
                address(0x0), // recipient address (can be contract or 0x0)
                block.timestamp
            );
        }
    }

    /// @notice Get list of tranches available for purchase
    /// @dev A tranche is available if its price is below or equal to current market price
    /// @return Array of booleans indicating if each tranche is available
    function getAvailableTranches() public view returns (bool[14] memory) {
        bool[14] memory availableTranches;
        uint256 currentPrice = getTokenPriceInETH();
        
        for (uint256 i = 0; i < priceMultiples.length; i++) {
            uint256 tranchePrice = initialPricePerToken * priceMultiples[i];
            if ((trancheSold[i] < trancheSupply[i]) && (currentPrice >= tranchePrice || i == 0)) {
                availableTranches[i] = true;
            } else {
                availableTranches[i] = false;
            }
        }
        
        return availableTranches;
    }

    /// @notice Get available tranches for a specific user
    /// @dev Combines general tranche availability with user-specific purchase limits
    /// @param user The address of the user to check
    /// @return Array of booleans indicating which tranches are available for the user
    function getUserAvailableTranches(address user) public view returns (bool[14] memory) {
        bool[14] memory availableTranches = getAvailableTranches();
        bool[14] memory userAvailable;
        
        for (uint256 i = 0; i < priceMultiples.length; i++) {
            if (availableTranches[i] && userTranchePurchases[user][i] < trancheMaxPurchase[i]) {
                userAvailable[i] = true;
            } else {
                userAvailable[i] = false;
            }
        }
        
        return userAvailable;
    }

    /// @notice Get current token price in ETH from Uniswap pool
    /// @dev Returns initial price if no liquidity exists
    /// @return Current price of token in ETH (scaled by 1e18)
    function getTokenPriceInETH() public view returns (uint256) {
        (uint112 reserve0, uint112 reserve1,) = IUniswapV2Pair(uniswapV2Pair).getReserves();
        if (reserve0 == 0 || reserve1 == 0) return initialPricePerToken;

        if (IUniswapV2Pair(uniswapV2Pair).token0() == address(this)) {
            return (uint256(reserve1) * 1e18) / uint256(reserve0);
        } else {
            return (uint256(reserve0) * 1e18) / uint256(reserve1);
        }
    }

    /// @notice Get the current Fully Diluted Valuation in ETH
    /// @return fdv The fully diluted valuation (totalSupply * price)
    function getFDV() public view returns (uint256 fdv) {
        if (!initialLiquidityDeployed) return 0;
        uint256 currentPrice = getTokenPriceInETH();
        fdv = (totalSupply() * currentPrice) / 1e18;
    }

    /// @notice Get the current Market Cap in ETH
    /// @return marketCap The market cap (circulating supply * price)
    function getMarketCap() public view returns (uint256 marketCap) {
        if (!initialLiquidityDeployed) return 0;
        uint256 currentPrice = getTokenPriceInETH();
        uint256 circulatingSupply = totalSupply() - balanceOf(address(this));
        marketCap = (circulatingSupply * currentPrice) / 1e18;
    }

    /// @notice Get the current total liquidity value in ETH
    /// @return liquidity The total liquidity value (ETH in pool * 2)
    function getLiquidity() public view returns (uint256 liquidity) {
        if (!initialLiquidityDeployed) return 0;
        address weth = uniswapV2Router.WETH();
        liquidity = IERC20(weth).balanceOf(address(uniswapV2Pair)) * 2;
    }

    /// @notice Get static contract configuration data
    /// @dev Returns immutable contract parameters and configuration set during deployment.
    /// @return _name Token name
    /// @return _symbol Token symbol
    /// @return _totalSupply Total token supply
    /// @return _initialPricePerToken Initial price per token in ETH (wei) for tranche 0
    /// @return _uniswapV2Pair Address of the created Uniswap V2 pair
    /// @return _priceMultiples Array of price multipliers defining the price for each tranche relative to the initial price
    /// @return _trancheMaxPurchase Array of maximum token purchase amounts per wallet for each tranche
    /// @return _trancheSupply Array of total token supply allocated to each tranche
    function getStaticContractData() public view returns (
        string memory _name,
        string memory _symbol,
        uint256 _totalSupply,
        uint256 _initialPricePerToken,
        address _uniswapV2Pair,
        uint256[14] memory _priceMultiples,
        uint256[14] memory _trancheMaxPurchase,
        uint256[14] memory _trancheSupply
    ) {
        return (
            name(),
            symbol(),
            totalSupply(),
            initialPricePerToken,
            address(uniswapV2Pair),
            priceMultiples,
            trancheMaxPurchase,
            trancheSupply
        );
    }

    /// @notice Get current contract state and market metrics
    /// @dev Returns dynamic data reflecting the current status of the sale and market conditions.
    /// @return _initialLiquidityDeployed Boolean indicating if initial liquidity has been deployed
    /// @return _trancheSold Array showing the amount of tokens sold in each tranche
    /// @return _availableTranches Boolean array indicating which tranches are currently available for purchase (price condition met and not sold out)
    /// @return _currentPriceETH Current token price in ETH (wei) fetched from the Uniswap pool
    /// @return _marketCap Current market capitalization in ETH (wei) based on circulating supply
    /// @return _fdv Current fully diluted valuation in ETH (wei) based on total supply
    /// @return _liquidity Current total liquidity value in ETH (wei) in the Uniswap pool (ETH balance * 2)
    function getDynamicContractData() public view returns (
        bool _initialLiquidityDeployed,
        uint256[14] memory _trancheSold,
        bool[14] memory _availableTranches,
        uint256 _currentPriceETH,
        uint256 _marketCap,
        uint256 _fdv,
        uint256 _liquidity
    ) {
        return (
            initialLiquidityDeployed,
            trancheSold,
            getAvailableTranches(),
            getTokenPriceInETH(),
            getMarketCap(),
            getFDV(),
            getLiquidity()
        );
    }

    /// @notice Get user-specific data and tranche participation
    /// @dev Returns data specific to a given user address.
    /// @param user Address of the user to query
    /// @return _balance User's current token balance
    /// @return _isInitialContributor Boolean indicating if the user participated in the initial tranche (tranche 0) purchase
    /// @return _tranchePurchases Array showing the total tokens purchased by the user in each tranche
    /// @return _trancheETHPaid Array showing the total ETH paid by the user for purchases in each tranche
    /// @return _userAvailableTranches Boolean array indicating which tranches are currently available for this specific user (combines general availability and user's wallet limit)
    function getUserData(address user) public view returns (
        uint256 _balance,
        bool _isInitialContributor,
        uint256[14] memory _tranchePurchases,
        uint256[14] memory _trancheETHPaid,
        bool[14] memory _userAvailableTranches
    ) {
        return (
            balanceOf(user),
            isInitialContributor[user],
            userTranchePurchases[user],
            userTrancheETHPaid[user],
            getUserAvailableTranches(user)
        );
    }

    /// @dev Overrides ERC20 _update function to add sniper protection.
    /// @dev Reverts if the transaction involves the Uniswap pair and the gas price priority fee exceeds `maxPriorityFee`.
    function _update(address from, address to, uint256 value) internal virtual override {
        // Add sniper protection for Uniswap interactions
        if (from == address(uniswapV2Pair) || to == address(uniswapV2Pair)) {
            if ((tx.gasprice - block.basefee) > maxPriorityFee) revert MaxPriorityFeeExceeded();
        }

        super._update(from, to, value);
    }

    /// @dev Overrides ERC20 transferFrom function. No functional change beyond standard OZ implementation, but added for explicitness.
    function transferFrom(address from, address to, uint256 value) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"uniswapV2Router_","type":"address"},{"internalType":"uint256","name":"totalSupply_","type":"uint256"},{"internalType":"uint256","name":"ethRaiseinWei_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"InitialSaleEnded","type":"error"},{"inputs":[],"name":"InsufficientETHBalance","type":"error"},{"inputs":[],"name":"InsufficientTokenBalance","type":"error"},{"inputs":[],"name":"InvalidPriceDifference","type":"error"},{"inputs":[],"name":"InvalidTrancheIndex","type":"error"},{"inputs":[],"name":"LiquidityDeployed","type":"error"},{"inputs":[],"name":"LiquidityNotDeployed","type":"error"},{"inputs":[],"name":"MaxPriorityFeeExceeded","type":"error"},{"inputs":[],"name":"NoRefundAvailable","type":"error"},{"inputs":[],"name":"PriceOutsideRange","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"TranchePriceExceedsMarket","type":"error"},{"inputs":[],"name":"TrancheSoldOut","type":"error"},{"inputs":[],"name":"WalletLimitReached","type":"error"},{"inputs":[],"name":"ZeroETHSent","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethSent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethUsed","type":"uint256"}],"name":"ExcessETHRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InitialTranchePurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InitialTrancheRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"trancheIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"TrancheCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"trancheIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TrancheTokensPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEEPR_AIRDROP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEEPR_VAULT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyInitialTranche","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"trancheIndex","type":"uint256"},{"internalType":"uint256","name":"maxPriceDifferencePercent","type":"uint256"}],"name":"buyTranche","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAvailableTranches","outputs":[{"internalType":"bool[14]","name":"","type":"bool[14]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDynamicContractData","outputs":[{"internalType":"bool","name":"_initialLiquidityDeployed","type":"bool"},{"internalType":"uint256[14]","name":"_trancheSold","type":"uint256[14]"},{"internalType":"bool[14]","name":"_availableTranches","type":"bool[14]"},{"internalType":"uint256","name":"_currentPriceETH","type":"uint256"},{"internalType":"uint256","name":"_marketCap","type":"uint256"},{"internalType":"uint256","name":"_fdv","type":"uint256"},{"internalType":"uint256","name":"_liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFDV","outputs":[{"internalType":"uint256","name":"fdv","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLiquidity","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMarketCap","outputs":[{"internalType":"uint256","name":"marketCap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStaticContractData","outputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_totalSupply","type":"uint256"},{"internalType":"uint256","name":"_initialPricePerToken","type":"uint256"},{"internalType":"address","name":"_uniswapV2Pair","type":"address"},{"internalType":"uint256[14]","name":"_priceMultiples","type":"uint256[14]"},{"internalType":"uint256[14]","name":"_trancheMaxPurchase","type":"uint256[14]"},{"internalType":"uint256[14]","name":"_trancheSupply","type":"uint256[14]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenPriceInETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserAvailableTranches","outputs":[{"internalType":"bool[14]","name":"","type":"bool[14]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserData","outputs":[{"internalType":"uint256","name":"_balance","type":"uint256"},{"internalType":"bool","name":"_isInitialContributor","type":"bool"},{"internalType":"uint256[14]","name":"_tranchePurchases","type":"uint256[14]"},{"internalType":"uint256[14]","name":"_trancheETHPaid","type":"uint256[14]"},{"internalType":"bool[14]","name":"_userAvailableTranches","type":"bool[14]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"initialContributors","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialLiquidityDeployed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialPricePerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isInitialContributor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPriorityFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"priceMultiples","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundInitialTranche","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trancheFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"trancheMaxPurchase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"trancheRelease","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"trancheSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"trancheSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV2Pair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapV2Router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userTrancheETHPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userTranchePurchases","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e0604052734f8411a4ff4e9ad6905612009cdcb8367602b4fc73ffffffffffffffffffffffffffffffffffffffff1660a09073ffffffffffffffffffffffffffffffffffffffff1681525073f08b1fe0cf1210f83a5f8c026c0fd4f717d195fe73ffffffffffffffffffffffffffffffffffffffff1660c09073ffffffffffffffffffffffffffffffffffffffff168152506103e8600855604051806101c00160405280600161ffff168152602001600561ffff168152602001600a61ffff168152602001601461ffff168152602001602861ffff168152602001605061ffff16815260200160a061ffff16815260200161014061ffff16815260200161028061ffff16815260200161050061ffff168152602001610a0061ffff16815260200161140061ffff16815260200161280061ffff16815260200161500061ffff16815250600a90600e6101539291906115e1565b50604051806101c0016040528061089861ffff16815260200161037061ffff16815260200161024e61ffff16815260200161018661ffff16815260200161010e61ffff16815260200160be61ffff168152602001608c61ffff168152602001606461ffff168152602001603c61ffff168152602001603261ffff168152602001602861ffff168152602001602861ffff168152602001601e61ffff168152602001601461ffff16815250601890600e61020d9291906115e1565b505f60505f6101000a81548160ff02191690831515021790555063b2d05e00605555604051615e96380380615e968339818101604052810190610250919061181c565b818181600390816102619190611ad2565b5080600490816102719190611ad2565b50505060016005819055503373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff168152505060185f600e81106102c4576102c3611ba1565b5b0154612710856102d49190611c28565b6102de9190611c58565b60345f600e81106102f2576102f1611ba1565b5b018190555060186001600e811061030c5761030b611ba1565b5b01546127108561031c9190611c28565b6103269190611c58565b60346001600e811061033b5761033a611ba1565b5b018190555060186002600e811061035557610354611ba1565b5b0154612710856103659190611c28565b61036f9190611c58565b60346002600e811061038457610383611ba1565b5b018190555060186003600e811061039e5761039d611ba1565b5b0154612710856103ae9190611c28565b6103b89190611c58565b60346003600e81106103cd576103cc611ba1565b5b018190555060186004600e81106103e7576103e6611ba1565b5b0154612710856103f79190611c28565b6104019190611c58565b60346004600e811061041657610415611ba1565b5b018190555060186005600e81106104305761042f611ba1565b5b0154612710856104409190611c28565b61044a9190611c58565b60346005600e811061045f5761045e611ba1565b5b018190555060186006600e811061047957610478611ba1565b5b0154612710856104899190611c28565b6104939190611c58565b60346006600e81106104a8576104a7611ba1565b5b018190555060186007600e81106104c2576104c1611ba1565b5b0154612710856104d29190611c28565b6104dc9190611c58565b60346007600e81106104f1576104f0611ba1565b5b018190555060186008600e811061050b5761050a611ba1565b5b01546127108561051b9190611c28565b6105259190611c58565b60346008600e811061053a57610539611ba1565b5b018190555060186009600e811061055457610553611ba1565b5b0154612710856105649190611c28565b61056e9190611c58565b60346009600e811061058357610582611ba1565b5b01819055506018600a600e811061059d5761059c611ba1565b5b0154612710856105ad9190611c28565b6105b79190611c58565b6034600a600e81106105cc576105cb611ba1565b5b01819055506018600b600e81106105e6576105e5611ba1565b5b0154612710856105f69190611c28565b6106009190611c58565b6034600b600e811061061557610614611ba1565b5b01819055506018600c600e811061062f5761062e611ba1565b5b01546127108561063f9190611c28565b6106499190611c58565b6034600c600e811061065e5761065d611ba1565b5b01819055506018600d600e811061067857610677611ba1565b5b0154612710856106889190611c28565b6106929190611c58565b6034600d600e81106106a7576106a6611ba1565b5b01819055506127106126ac60345f600e81106106c6576106c5611ba1565b5b01546106d29190611c58565b6106dc9190611c28565b60265f600e81106106f0576106ef611ba1565b5b01819055506127106101f460346001600e81106107105761070f611ba1565b5b015461071c9190611c58565b6107269190611c28565b60266001600e811061073b5761073a611ba1565b5b01819055506127106101f460346002600e811061075b5761075a611ba1565b5b01546107679190611c58565b6107719190611c28565b60266002600e811061078657610785611ba1565b5b01819055506127106103e860346003600e81106107a6576107a5611ba1565b5b01546107b29190611c58565b6107bc9190611c28565b60266003600e81106107d1576107d0611ba1565b5b01819055506127106103e860346004600e81106107f1576107f0611ba1565b5b01546107fd9190611c58565b6108079190611c28565b60266004600e811061081c5761081b611ba1565b5b01819055506127106103e860346005600e811061083c5761083b611ba1565b5b01546108489190611c58565b6108529190611c28565b60266005600e811061086757610866611ba1565b5b01819055506127106107d060346006600e811061088757610886611ba1565b5b01546108939190611c58565b61089d9190611c28565b60266006600e81106108b2576108b1611ba1565b5b01819055506127106107d060346007600e81106108d2576108d1611ba1565b5b01546108de9190611c58565b6108e89190611c28565b60266007600e81106108fd576108fc611ba1565b5b01819055506127106107d060346008600e811061091d5761091c611ba1565b5b01546109299190611c58565b6109339190611c28565b60266008600e811061094857610947611ba1565b5b018190555060346009600e811061096257610961611ba1565b5b015460266009600e811061097957610978611ba1565b5b01819055506034600a600e811061099357610992611ba1565b5b01546026600a600e81106109aa576109a9611ba1565b5b01819055506034600b600e81106109c4576109c3611ba1565b5b01546026600b600e81106109db576109da611ba1565b5b01819055506034600c600e81106109f5576109f4611ba1565b5b01546026600c600e8110610a0c57610a0b611ba1565b5b01819055506034600d600e8110610a2657610a25611ba1565b5b01546026600d600e8110610a3d57610a3c611ba1565b5b01819055508460065f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aec573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b109190611c99565b73ffffffffffffffffffffffffffffffffffffffff1663c9c653963060065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b96573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bba9190611c99565b6040518363ffffffff1660e01b8152600401610bd7929190611cd3565b6020604051808303815f875af1158015610bf3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c179190611c99565b60075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060345f600e8110610c6a57610c69611ba1565b5b0154670de0b6b3a764000084610c809190611c58565b610c8a9190611c28565b600981905550610ca030856110e860201b60201c565b5f3411156110de5760345f600e8110610cbc57610cbb611ba1565b5b015460425f600e8110610cd257610cd1611ba1565b5b015410610d0b576040517fdf8e376800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60265f600e8110610d1f57610d1e611ba1565b5b015460535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110610d7057610d6f611ba1565b5b015410610da9576040517f84dab64600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610dbd5f3460095461116d60201b60201c565b90505f670de0b6b3a764000060095483610dd79190611c58565b610de19190611c28565b905060525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16610ee757605133908060018154018082558091505060019003905f5260205f20015f9091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b8160425f600e8110610efc57610efb611ba1565b5b015f828254610f0b9190611cfa565b925050819055508160535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110610f6257610f61611ba1565b5b015f828254610f719190611cfa565b925050819055508060545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110610fc857610fc7611ba1565b5b015f828254610fd79190611cfa565b925050819055508034111561108d575f8134610ff39190611d2d565b90503373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611038573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167fc4e47ebda5850aad45eb70501556332e9d7a5664e604b34512efaee263aa0d4682348560405161108393929190611d6f565b60405180910390a2505b3373ffffffffffffffffffffffffffffffffffffffff167f3082f48ea05b3fcc96a3f50b9bd103f75800860568f3320fcedeb6de6d0dce21836040516110d39190611da4565b60405180910390a250505b5050505050611e0b565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611158575f6040517fec442f0500000000000000000000000000000000000000000000000000000000815260040161114f9190611dbd565b60405180910390fd5b6111695f838361127860201b60201c565b5050565b5f5f820361117d575f9050611271565b5f82670de0b6b3a7640000856111939190611c58565b61119d9190611c28565b90505f60535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2086600e81106111ef576111ee611ba1565b5b0154602687600e811061120557611204611ba1565b5b01546112119190611d2d565b90505f604287600e811061122857611227611ba1565b5b0154603488600e811061123e5761123d611ba1565b5b015461124a9190611d2d565b905061126b61125f848361138260201b60201c565b8361138260201b60201c565b93505050505b9392505050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16148061131f575060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1561136c57605554483a6113339190611d2d565b111561136b576040517ff441e9e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b61137d83838361139e60201b60201c565b505050565b5f61139682841084846115b760201b60201c565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036113ee578060025f8282546113e29190611cfa565b925050819055506114bc565b5f5f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015611477578381836040517fe450d38c00000000000000000000000000000000000000000000000000000000815260040161146e93929190611dd6565b60405180910390fd5b8181035f5f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611503578060025f828254039250508190555061154d565b805f5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516115aa9190611da4565b60405180910390a3505050565b5f6115c7846115d660201b60201c565b82841802821890509392505050565b5f8115159050919050565b82600e8101928215611616579160200282015b82811115611615578251829061ffff169055916020019190600101906115f4565b5b5090506116239190611627565b5090565b5b8082111561163e575f815f905550600101611628565b5090565b5f604051905090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61167c82611653565b9050919050565b61168c81611672565b8114611696575f5ffd5b50565b5f815190506116a781611683565b92915050565b5f819050919050565b6116bf816116ad565b81146116c9575f5ffd5b50565b5f815190506116da816116b6565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61172e826116e8565b810181811067ffffffffffffffff8211171561174d5761174c6116f8565b5b80604052505050565b5f61175f611642565b905061176b8282611725565b919050565b5f67ffffffffffffffff82111561178a576117896116f8565b5b611793826116e8565b9050602081019050919050565b8281835e5f83830152505050565b5f6117c06117bb84611770565b611756565b9050828152602081018484840111156117dc576117db6116e4565b5b6117e78482856117a0565b509392505050565b5f82601f830112611803576118026116e0565b5b81516118138482602086016117ae565b91505092915050565b5f5f5f5f5f60a086880312156118355761183461164b565b5b5f61184288828901611699565b9550506020611853888289016116cc565b9450506040611864888289016116cc565b935050606086015167ffffffffffffffff8111156118855761188461164f565b5b611891888289016117ef565b925050608086015167ffffffffffffffff8111156118b2576118b161164f565b5b6118be888289016117ef565b9150509295509295909350565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061191957607f821691505b60208210810361192c5761192b6118d5565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f6008830261198e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82611953565b6119988683611953565b95508019841693508086168417925050509392505050565b5f819050919050565b5f6119d36119ce6119c9846116ad565b6119b0565b6116ad565b9050919050565b5f819050919050565b6119ec836119b9565b611a006119f8826119da565b84845461195f565b825550505050565b5f5f905090565b611a17611a08565b611a228184846119e3565b505050565b5b81811015611a4557611a3a5f82611a0f565b600181019050611a28565b5050565b601f821115611a8a57611a5b81611932565b611a6484611944565b81016020851015611a73578190505b611a87611a7f85611944565b830182611a27565b50505b505050565b5f82821c905092915050565b5f611aaa5f1984600802611a8f565b1980831691505092915050565b5f611ac28383611a9b565b9150826002028217905092915050565b611adb826118cb565b67ffffffffffffffff811115611af457611af36116f8565b5b611afe8254611902565b611b09828285611a49565b5f60209050601f831160018114611b3a575f8415611b28578287015190505b611b328582611ab7565b865550611b99565b601f198416611b4886611932565b5f5b82811015611b6f57848901518255600182019150602085019450602081019050611b4a565b86831015611b8c5784890151611b88601f891682611a9b565b8355505b6001600288020188555050505b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611c32826116ad565b9150611c3d836116ad565b925082611c4d57611c4c611bce565b5b828204905092915050565b5f611c62826116ad565b9150611c6d836116ad565b9250828202611c7b816116ad565b91508282048414831517611c9257611c91611bfb565b5b5092915050565b5f60208284031215611cae57611cad61164b565b5b5f611cbb84828501611699565b91505092915050565b611ccd81611672565b82525050565b5f604082019050611ce65f830185611cc4565b611cf36020830184611cc4565b9392505050565b5f611d04826116ad565b9150611d0f836116ad565b9250828201905080821115611d2757611d26611bfb565b5b92915050565b5f611d37826116ad565b9150611d42836116ad565b9250828203905081811115611d5a57611d59611bfb565b5b92915050565b611d69816116ad565b82525050565b5f606082019050611d825f830186611d60565b611d8f6020830185611d60565b611d9c6040830184611d60565b949350505050565b5f602082019050611db75f830184611d60565b92915050565b5f602082019050611dd05f830184611cc4565b92915050565b5f606082019050611de95f830186611cc4565b611df66020830185611d60565b611e036040830184611d60565b949350505050565b60805160a05160c05161404c611e4a5f395f81816116f30152612ead01525f818161252c0152612e3c01525f818161256d0152612dcf015261404c5ff3fe608060405260043610610233575f3560e01c806370a082311161012d578063ba3cfea8116100aa578063dc4c13281161006e578063dc4c132814610881578063dd62ed3e146108ab578063e681e785146108e7578063f2368ce214610923578063ffc9896b146109535761023a565b8063ba3cfea814610796578063c161085a146107c7578063c5353b13146107f1578063ce4cf7d81461081b578063d5f39488146108575761023a565b806390825c28116100f157806390825c281461068e57806395d89b41146106b85780639f77bfca146106e2578063a9059cbb1461071e578063ad5e38e11461075a5761023a565b806370a08231146105ba57806380184e12146105f657806383a58544146106205780638d187d391461065c5780638f4ec825146106785761023a565b806329318897116101bb57806349bd5a5e1161017f57806349bd5a5e146104c457806358382b7b146104ee57806361bba3811461052a5780636db5339a146105545780636dbc636a1461057e5761023a565b806329318897146103ee578063313ce56714610418578063357d841a1461044257806338b442831461044c578063486921c7146104885761023a565b80631694505e116102025780631694505e1461030a57806318160ddd14610334578063239422ea1461035e57806323b872dd14610388578063265899c2146103c45761023a565b8063037e68841461023e57806306fdde031461027a5780630910a510146102a4578063095ea7b3146102ce5761023a565b3661023a57005b5f5ffd5b348015610249575f5ffd5b50610264600480360381019061025f9190613566565b610993565b6040516102719190613641565b60405180910390f35b348015610285575f5ffd5b5061028e610aae565b60405161029b91906136cb565b60405180910390f35b3480156102af575f5ffd5b506102b8610b3e565b6040516102c59190613703565b60405180910390f35b3480156102d9575f5ffd5b506102f460048036038101906102ef9190613746565b610c97565b6040516103019190613793565b60405180910390f35b348015610315575f5ffd5b5061031e610cb9565b60405161032b9190613807565b60405180910390f35b34801561033f575f5ffd5b50610348610cde565b6040516103559190613703565b60405180910390f35b348015610369575f5ffd5b50610372610ce7565b60405161037f9190613793565b60405180910390f35b348015610393575f5ffd5b506103ae60048036038101906103a99190613820565b610cf9565b6040516103bb9190613793565b60405180910390f35b3480156103cf575f5ffd5b506103d8610d27565b6040516103e59190613641565b60405180910390f35b3480156103f9575f5ffd5b50610402610e22565b60405161040f9190613703565b60405180910390f35b348015610423575f5ffd5b5061042c611045565b604051610439919061388b565b60405180910390f35b61044a61104d565b005b348015610457575f5ffd5b50610472600480360381019061046d9190613746565b611617565b60405161047f9190613703565b60405180910390f35b348015610493575f5ffd5b506104ae60048036038101906104a99190613746565b61163b565b6040516104bb9190613703565b60405180910390f35b3480156104cf575f5ffd5b506104d861165f565b6040516104e591906138c4565b60405180910390f35b3480156104f9575f5ffd5b50610514600480360381019061050f91906138dd565b611684565b6040516105219190613703565b60405180910390f35b348015610535575f5ffd5b5061053e61169d565b60405161054b9190613703565b60405180910390f35b34801561055f575f5ffd5b506105686116f1565b6040516105759190613917565b60405180910390f35b348015610589575f5ffd5b506105a4600480360381019061059f91906138dd565b611715565b6040516105b19190613917565b60405180910390f35b3480156105c5575f5ffd5b506105e060048036038101906105db9190613566565b611750565b6040516105ed9190613703565b60405180910390f35b348015610601575f5ffd5b5061060a611795565b6040516106179190613703565b60405180910390f35b34801561062b575f5ffd5b50610646600480360381019061064191906138dd565b61179b565b6040516106539190613703565b60405180910390f35b61067660048036038101906106719190613930565b6117b4565b005b348015610683575f5ffd5b5061068c611dd9565b005b348015610699575f5ffd5b506106a261229c565b6040516106af9190613703565b60405180910390f35b3480156106c3575f5ffd5b506106cc612308565b6040516106d991906136cb565b60405180910390f35b3480156106ed575f5ffd5b50610708600480360381019061070391906138dd565b612398565b6040516107159190613703565b60405180910390f35b348015610729575f5ffd5b50610744600480360381019061073f9190613746565b6123b1565b6040516107519190613793565b60405180910390f35b348015610765575f5ffd5b50610780600480360381019061077b91906138dd565b6123d3565b60405161078d9190613703565b60405180910390f35b3480156107a1575f5ffd5b506107aa6123ec565b6040516107be989796959493929190613a13565b60405180910390f35b3480156107d2575f5ffd5b506107db612524565b6040516107e89190613703565b60405180910390f35b3480156107fc575f5ffd5b5061080561252a565b6040516108129190613917565b60405180910390f35b348015610826575f5ffd5b50610841600480360381019061083c9190613566565b61254e565b60405161084e9190613793565b60405180910390f35b348015610862575f5ffd5b5061086b61256b565b6040516108789190613917565b60405180910390f35b34801561088c575f5ffd5b5061089561258f565b6040516108a29190613703565b60405180910390f35b3480156108b6575f5ffd5b506108d160048036038101906108cc9190613a9f565b612595565b6040516108de9190613703565b60405180910390f35b3480156108f2575f5ffd5b5061090d600480360381019061090891906138dd565b612617565b60405161091a9190613703565b60405180910390f35b34801561092e575f5ffd5b50610937612630565b60405161094a9796959493929190613add565b60405180910390f35b34801561095e575f5ffd5b5061097960048036038101906109749190613566565b6126d4565b60405161098a959493929190613b50565b60405180910390f35b61099b6134c2565b5f6109a4610d27565b90506109ae6134c2565b5f5f90505b600e811015610aa3578281600e81106109cf576109ce613ba4565b5b60200201518015610a445750602681600e81106109ef576109ee613ba4565b5b015460535f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2082600e8110610a4057610a3f613ba4565b5b0154105b15610a725760018282600e8110610a5e57610a5d613ba4565b5b602002019015159081151581525050610a96565b5f8282600e8110610a8657610a85613ba4565b5b6020020190151590811515815250505b80806001019150506109b3565b508092505050919050565b606060038054610abd90613bfe565b80601f0160208091040260200160405190810160405280929190818152602001828054610ae990613bfe565b8015610b345780601f10610b0b57610100808354040283529160200191610b34565b820191905f5260205f20905b815481529060010190602001808311610b1757829003601f168201915b5050505050905090565b5f60505f9054906101000a900460ff16610b5a575f9050610c94565b5f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610be99190613c42565b905060028173ffffffffffffffffffffffffffffffffffffffff166370a0823160075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401610c479190613917565b602060405180830381865afa158015610c62573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c869190613c81565b610c909190613cd9565b9150505b90565b5f5f610ca1612855565b9050610cae81858561285c565b600191505092915050565b60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f600254905090565b60505f9054906101000a900460ff1681565b5f5f610d03612855565b9050610d1085828561286e565b610d1b858585612901565b60019150509392505050565b610d2f6134c2565b610d376134c2565b5f610d40610e22565b90505f5f90505b600e811015610e19575f600a82600e8110610d6557610d64613ba4565b5b0154600954610d749190613cd9565b9050603482600e8110610d8a57610d89613ba4565b5b0154604283600e8110610da057610d9f613ba4565b5b0154108015610db957508083101580610db857505f82145b5b15610de75760018483600e8110610dd357610dd2613ba4565b5b602002019015159081151581525050610e0b565b5f8483600e8110610dfb57610dfa613ba4565b5b6020020190151590811515815250505b508080600101915050610d47565b50819250505090565b5f5f5f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610e8f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eb39190613d96565b50915091505f826dffffffffffffffffffffffffffff161480610ee557505f816dffffffffffffffffffffffffffff16145b15610ef65760095492505050611042565b3073ffffffffffffffffffffffffffffffffffffffff1660075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f77573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9b9190613c42565b73ffffffffffffffffffffffffffffffffffffffff1603610ffe57816dffffffffffffffffffffffffffff16670de0b6b3a7640000826dffffffffffffffffffffffffffff16610feb9190613cd9565b610ff59190613e13565b92505050611042565b806dffffffffffffffffffffffffffff16670de0b6b3a7640000836dffffffffffffffffffffffffffff166110339190613cd9565b61103d9190613e13565b925050505b90565b5f6012905090565b6110556129f1565b605554483a6110649190613e43565b111561109c576040517ff441e9e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60505f9054906101000a900460ff16156110e2576040517f1ad8494f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f340361111b576040517f19a1bf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60345f600e811061112f5761112e613ba4565b5b015460425f600e811061114557611144613ba4565b5b01541061117e576040517fdf8e376800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60265f600e811061119257611191613ba4565b5b015460535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e81106111e3576111e2613ba4565b5b01541061121c576040517f84dab64600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61122a5f34600954612a37565b90505f670de0b6b3a7640000600954836112449190613cd9565b61124e9190613e13565b90508060545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e81106112a05761129f613ba4565b5b015f8282546112af9190613e76565b9250508190555060525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166113ba57605133908060018154018082558091505060019003905f5260205f20015f9091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b8160425f600e81106113cf576113ce613ba4565b5b015f8282546113de9190613e76565b925050819055508160535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e811061143557611434613ba4565b5b015f8282546114449190613e76565b92505081905550803411156114fa575f81346114609190613e43565b90503373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156114a5573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167fc4e47ebda5850aad45eb70501556332e9d7a5664e604b34512efaee263aa0d468234856040516114f093929190613ea9565b60405180910390a2505b60345f600e811061150e5761150d613ba4565b5b015460425f600e811061152457611523613ba4565b5b01541061153c57611533612b36565b61153b612c54565b5b60345f600e81106115505761154f613ba4565b5b015460425f600e811061156657611565613ba4565b5b0154106115bd575f7f2946ed324b02a3995b07e07216a2f5c83e8dc9e4b52eab07770fdbd1af0ef4cc60425f600e81106115a3576115a2613ba4565b5b0154436040516115b4929190613ede565b60405180910390a25b3373ffffffffffffffffffffffffffffffffffffffff167f3082f48ea05b3fcc96a3f50b9bd103f75800860568f3320fcedeb6de6d0dce21836040516116039190613703565b60405180910390a25050611615612cd2565b565b6053602052815f5260405f2081600e8110611630575f80fd5b015f91509150505481565b6054602052815f5260405f2081600e8110611654575f80fd5b015f91509150505481565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b602681600e8110611693575f80fd5b015f915090505481565b5f60505f9054906101000a900460ff166116b9575f90506116ee565b5f6116c2610e22565b9050670de0b6b3a7640000816116d6610cde565b6116e09190613cd9565b6116ea9190613e13565b9150505b90565b7f000000000000000000000000000000000000000000000000000000000000000081565b60518181548110611724575f80fd5b905f5260205f20015f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b60555481565b603481600e81106117aa575f80fd5b015f915090505481565b6117bc6129f1565b605554483a6117cb9190613e43565b1115611803576040517ff441e9e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60505f9054906101000a900460ff16611848576040517fdff61f8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f3403611881576040517f19a1bf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8214806118905750600e8210155b156118c7576040517f4e2a8dfe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064811015611902576040517fabcca32100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603482600e811061191657611915613ba4565b5b0154604283600e811061192c5761192b613ba4565b5b015410611965576040517fdf8e376800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602682600e811061197957611978613ba4565b5b015460535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2083600e81106119ca576119c9613ba4565b5b015410611a03576040517f84dab64600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611a0c610e22565b90505f600a84600e8110611a2357611a22613ba4565b5b0154600954611a329190613cd9565b905080821015611a6e576040517f85fecc1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127108382611a7d9190613cd9565b611a879190613e13565b81611a929190613e76565b821115611acb576040517fe10dffe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611ad7853485612a37565b90505f670de0b6b3a76400008483611aef9190613cd9565b611af99190613e13565b905081611b0530611750565b1015611b3d576040517fe4455cae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b478282612cdc565b81604287600e8110611b5c57611b5b613ba4565b5b015f828254611b6b9190613e76565b925050819055508160535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2087600e8110611bc257611bc1613ba4565b5b015f828254611bd19190613e76565b925050819055508060545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2087600e8110611c2857611c27613ba4565b5b015f828254611c379190613e76565b9250508190555080341115611ced575f8134611c539190613e43565b90503373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611c98573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167fc4e47ebda5850aad45eb70501556332e9d7a5664e604b34512efaee263aa0d46823485604051611ce393929190613ea9565b60405180910390a2505b611cf8303384612901565b603486600e8110611d0c57611d0b613ba4565b5b0154604287600e8110611d2257611d21613ba4565b5b015410611d7957857f2946ed324b02a3995b07e07216a2f5c83e8dc9e4b52eab07770fdbd1af0ef4cc604288600e8110611d5f57611d5e613ba4565b5b015443604051611d70929190613ede565b60405180910390a25b3373ffffffffffffffffffffffffffffffffffffffff167ff3fb67cb71e333dcc656ea2a2a916481a2e5b06ae89e35f667813fc7043e08ad8784604051611dc1929190613ede565b60405180910390a250505050611dd5612cd2565b5050565b611de16129f1565b60505f9054906101000a900460ff1615611e27576040517f1ad8494f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110611e7757611e76613ba4565b5b015490505f8103611eb4576040517fe49c14cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110611f0457611f03613ba4565b5b015490505f60535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110611f5857611f57613ba4565b5b01819055505f60545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110611fad57611fac613ba4565b5b01819055508160425f600e8110611fc757611fc6613ba4565b5b015f828254611fd69190613e43565b9250508190555060525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16156121fe575f60525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505f5f90505b6051805490508110156121fc573373ffffffffffffffffffffffffffffffffffffffff16605182815481106120bd576120bc613ba4565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036121ef57605160016051805490506121149190613e43565b8154811061212557612124613ba4565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166051828154811061216157612160613ba4565b5b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060518054806121b8576121b7613f05565b5b600190038181905f5260205f20015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590556121fc565b8080600101915050612085565b505b3373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015612241573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167f35cc6ad8d7e55fcdb00bb23c90df11f0368befe6d3f7e748ee24f5f88810b3e5836040516122889190613703565b60405180910390a2505061229a612cd2565b565b5f60505f9054906101000a900460ff166122b8575f9050612305565b5f6122c1610e22565b90505f6122cd30611750565b6122d5610cde565b6122df9190613e43565b9050670de0b6b3a764000082826122f69190613cd9565b6123009190613e13565b925050505b90565b60606004805461231790613bfe565b80601f016020809104026020016040519081016040528092919081815260200182805461234390613bfe565b801561238e5780601f106123655761010080835404028352916020019161238e565b820191905f5260205f20905b81548152906001019060200180831161237157829003601f168201915b5050505050905090565b600a81600e81106123a7575f80fd5b015f915090505481565b5f5f6123bb612855565b90506123c8818585612901565b600191505092915050565b601881600e81106123e2575f80fd5b015f915090505481565b6060805f5f5f6123fa6134e5565b6124026134e5565b61240a6134e5565b612412610aae565b61241a612308565b612422610cde565b60095460075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600a6026603482600e806020026040519081016040528092919082600e8015612485576020028201915b815481526020019060010190808311612471575b5050505050925081600e806020026040519081016040528092919082600e80156124c4576020028201915b8154815260200190600101908083116124b0575b5050505050915080600e806020026040519081016040528092919082600e8015612503576020028201915b8154815260200190600101908083116124ef575b50505050509050975097509750975097509750975097509091929394959697565b60085481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6052602052805f5260405f205f915054906101000a900460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b60095481565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b604281600e8110612626575f80fd5b015f915090505481565b5f6126396134e5565b6126416134c2565b5f5f5f5f60505f9054906101000a900460ff16604261265e610d27565b612666610e22565b61266e61229c565b61267661169d565b61267e610b3e565b85600e806020026040519081016040528092919082600e80156126b6576020028201915b8154815260200190600101908083116126a2575b50505050509550965096509650965096509650965090919293949596565b5f5f6126de6134e5565b6126e66134e5565b6126ee6134c2565b6126f786611750565b60525f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1660535f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060545f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206127c48a610993565b82600e806020026040519081016040528092919082600e80156127fc576020028201915b8154815260200190600101908083116127e8575b5050505050925081600e806020026040519081016040528092919082600e801561283b576020028201915b815481526020019060010190808311612827575b505050505091509450945094509450945091939590929450565b5f33905090565b6128698383836001612f9c565b505050565b5f6128798484612595565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156128fb57818110156128ec578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016128e393929190613f32565b60405180910390fd5b6128fa84848484035f612f9c565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612971575f6040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081526004016129689190613917565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129e1575f6040517fec442f050000000000000000000000000000000000000000000000000000000081526004016129d89190613917565b60405180910390fd5b6129ec83838361316b565b505050565b600260055403612a2d576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600581905550565b5f5f8203612a47575f9050612b2f565b5f82670de0b6b3a764000085612a5d9190613cd9565b612a679190613e13565b90505f60535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2086600e8110612ab957612ab8613ba4565b5b0154602687600e8110612acf57612ace613ba4565b5b0154612adb9190613e43565b90505f604287600e8110612af257612af1613ba4565b5b0154603488600e8110612b0857612b07613ba4565b5b0154612b149190613e43565b9050612b29612b23848361326f565b8361326f565b93505050505b9392505050565b5f5f90505b605180549050811015612c51575f60518281548110612b5d57612b5c613ba4565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f60535f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110612bd757612bd6613ba4565b5b015490505f811115612c4457612bee308383612901565b5f60535f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110612c3e57612c3d613ba4565b5b01819055505b8260010192505050612b3b565b50565b5f4703612c8d576040517fbbb20aae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f4790505f60345f600e8110612ca657612ca5613ba4565b5b01549050612cb48183612cdc565b600160505f6101000a81548160ff0219169083151502179055505050565b6001600581905550565b5f61271060085484612cee9190613cd9565b612cf89190613e13565b90505f61271060085484612d0c9190613cd9565b612d169190613e13565b90505f6064604b83612d289190613cd9565b612d329190613e13565b90505f8183612d419190613e43565b90505f8487612d509190613e43565b90505f8487612d5f9190613e43565b90505f6064605f84612d719190613cd9565b612d7b9190613e13565b90505f6064605f84612d8d9190613cd9565b612d979190613e13565b9050612dc53060065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168661285c565b5f861115612e32577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015612e30573d5f5f3e3d5ffd5b505b5f851115612e9f577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015612e9d573d5f5f3e3d5ffd5b505b5f881115612ed357612ed2307f00000000000000000000000000000000000000000000000000000000000000008a612901565b5b5f84118015612ee157505f83115b15612f905760065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f305d71984308786865f426040518863ffffffff1660e01b8152600401612f4b96959493929190613f67565b60606040518083038185885af1158015612f67573d5f5f3e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190612f8c9190613fc6565b5050505b50505050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361300c575f6040517fe602df050000000000000000000000000000000000000000000000000000000081526004016130039190613917565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361307c575f6040517f94280d620000000000000000000000000000000000000000000000000000000081526004016130739190613917565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508015613165578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161315c9190613703565b60405180910390a35b50505050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480613212575060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1561325f57605554483a6132269190613e43565b111561325e576040517ff441e9e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b61326a838383613285565b505050565b5f61327d828410848461349e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036132d5578060025f8282546132c99190613e76565b925050819055506133a3565b5f5f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490508181101561335e578381836040517fe450d38c00000000000000000000000000000000000000000000000000000000815260040161335593929190613f32565b60405180910390fd5b8181035f5f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036133ea578060025f8282540392505081905550613434565b805f5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516134919190613703565b60405180910390a3505050565b5f6134a8846134b7565b82841802821890509392505050565b5f8115159050919050565b604051806101c00160405280600e90602082028036833780820191505090505090565b604051806101c00160405280600e90602082028036833780820191505090505090565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6135358261350c565b9050919050565b6135458161352b565b811461354f575f5ffd5b50565b5f813590506135608161353c565b92915050565b5f6020828403121561357b5761357a613508565b5b5f61358884828501613552565b91505092915050565b5f600e9050919050565b5f81905092915050565b5f819050919050565b5f8115159050919050565b6135c2816135ae565b82525050565b5f6135d383836135b9565b60208301905092915050565b5f602082019050919050565b6135f481613591565b6135fe818461359b565b9250613609826135a5565b805f5b8381101561363957815161362087826135c8565b965061362b836135df565b92505060018101905061360c565b505050505050565b5f6101c0820190506136555f8301846135eb565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61369d8261365b565b6136a78185613665565b93506136b7818560208601613675565b6136c081613683565b840191505092915050565b5f6020820190508181035f8301526136e38184613693565b905092915050565b5f819050919050565b6136fd816136eb565b82525050565b5f6020820190506137165f8301846136f4565b92915050565b613725816136eb565b811461372f575f5ffd5b50565b5f813590506137408161371c565b92915050565b5f5f6040838503121561375c5761375b613508565b5b5f61376985828601613552565b925050602061377a85828601613732565b9150509250929050565b61378d816135ae565b82525050565b5f6020820190506137a65f830184613784565b92915050565b5f819050919050565b5f6137cf6137ca6137c58461350c565b6137ac565b61350c565b9050919050565b5f6137e0826137b5565b9050919050565b5f6137f1826137d6565b9050919050565b613801816137e7565b82525050565b5f60208201905061381a5f8301846137f8565b92915050565b5f5f5f6060848603121561383757613836613508565b5b5f61384486828701613552565b935050602061385586828701613552565b925050604061386686828701613732565b9150509250925092565b5f60ff82169050919050565b61388581613870565b82525050565b5f60208201905061389e5f83018461387c565b92915050565b5f6138ae826137d6565b9050919050565b6138be816138a4565b82525050565b5f6020820190506138d75f8301846138b5565b92915050565b5f602082840312156138f2576138f1613508565b5b5f6138ff84828501613732565b91505092915050565b6139118161352b565b82525050565b5f60208201905061392a5f830184613908565b92915050565b5f5f6040838503121561394657613945613508565b5b5f61395385828601613732565b925050602061396485828601613732565b9150509250929050565b5f600e9050919050565b5f81905092915050565b5f819050919050565b613994816136eb565b82525050565b5f6139a5838361398b565b60208301905092915050565b5f602082019050919050565b6139c68161396e565b6139d08184613978565b92506139db82613982565b805f5b83811015613a0b5781516139f2878261399a565b96506139fd836139b1565b9250506001810190506139de565b505050505050565b5f6105e0820190508181035f830152613a2c818b613693565b90508181036020830152613a40818a613693565b9050613a4f60408301896136f4565b613a5c60608301886136f4565b613a696080830187613908565b613a7660a08301866139bd565b613a846102608301856139bd565b613a926104208301846139bd565b9998505050505050505050565b5f5f60408385031215613ab557613ab4613508565b5b5f613ac285828601613552565b9250506020613ad385828601613552565b9150509250929050565b5f61042082019050613af15f83018a613784565b613afe60208301896139bd565b613b0c6101e08301886135eb565b613b1a6103a08301876136f4565b613b286103c08301866136f4565b613b366103e08301856136f4565b613b446104008301846136f4565b98975050505050505050565b5f61058082019050613b645f8301886136f4565b613b716020830187613784565b613b7e60408301866139bd565b613b8c6102008301856139bd565b613b9a6103c08301846135eb565b9695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680613c1557607f821691505b602082108103613c2857613c27613bd1565b5b50919050565b5f81519050613c3c8161353c565b92915050565b5f60208284031215613c5757613c56613508565b5b5f613c6484828501613c2e565b91505092915050565b5f81519050613c7b8161371c565b92915050565b5f60208284031215613c9657613c95613508565b5b5f613ca384828501613c6d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f613ce3826136eb565b9150613cee836136eb565b9250828202613cfc816136eb565b91508282048414831517613d1357613d12613cac565b5b5092915050565b5f6dffffffffffffffffffffffffffff82169050919050565b613d3c81613d1a565b8114613d46575f5ffd5b50565b5f81519050613d5781613d33565b92915050565b5f63ffffffff82169050919050565b613d7581613d5d565b8114613d7f575f5ffd5b50565b5f81519050613d9081613d6c565b92915050565b5f5f5f60608486031215613dad57613dac613508565b5b5f613dba86828701613d49565b9350506020613dcb86828701613d49565b9250506040613ddc86828701613d82565b9150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613e1d826136eb565b9150613e28836136eb565b925082613e3857613e37613de6565b5b828204905092915050565b5f613e4d826136eb565b9150613e58836136eb565b9250828203905081811115613e7057613e6f613cac565b5b92915050565b5f613e80826136eb565b9150613e8b836136eb565b9250828201905080821115613ea357613ea2613cac565b5b92915050565b5f606082019050613ebc5f8301866136f4565b613ec960208301856136f4565b613ed660408301846136f4565b949350505050565b5f604082019050613ef15f8301856136f4565b613efe60208301846136f4565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f606082019050613f455f830186613908565b613f5260208301856136f4565b613f5f60408301846136f4565b949350505050565b5f60c082019050613f7a5f830189613908565b613f8760208301886136f4565b613f9460408301876136f4565b613fa160608301866136f4565b613fae6080830185613908565b613fbb60a08301846136f4565b979650505050505050565b5f5f5f60608486031215613fdd57613fdc613508565b5b5f613fea86828701613c6d565b9350506020613ffb86828701613c6d565b925050604061400c86828701613c6d565b915050925092509256fea26469706673582212205df1b214cf8e9a2355c03f81f34f6766998a77b643b3621e03229f0524d8b62064736f6c634300081e00330000000000000000000000004752ba5dbc23f44d87826276bf6fd6b1c372ad2400000000000000000000000000000000000000000052b7d2dcc80cd2e4000000000000000000000000000000000000000000000000000000061b31ab352c000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000944656570722e66756e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054445455052000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405260043610610233575f3560e01c806370a082311161012d578063ba3cfea8116100aa578063dc4c13281161006e578063dc4c132814610881578063dd62ed3e146108ab578063e681e785146108e7578063f2368ce214610923578063ffc9896b146109535761023a565b8063ba3cfea814610796578063c161085a146107c7578063c5353b13146107f1578063ce4cf7d81461081b578063d5f39488146108575761023a565b806390825c28116100f157806390825c281461068e57806395d89b41146106b85780639f77bfca146106e2578063a9059cbb1461071e578063ad5e38e11461075a5761023a565b806370a08231146105ba57806380184e12146105f657806383a58544146106205780638d187d391461065c5780638f4ec825146106785761023a565b806329318897116101bb57806349bd5a5e1161017f57806349bd5a5e146104c457806358382b7b146104ee57806361bba3811461052a5780636db5339a146105545780636dbc636a1461057e5761023a565b806329318897146103ee578063313ce56714610418578063357d841a1461044257806338b442831461044c578063486921c7146104885761023a565b80631694505e116102025780631694505e1461030a57806318160ddd14610334578063239422ea1461035e57806323b872dd14610388578063265899c2146103c45761023a565b8063037e68841461023e57806306fdde031461027a5780630910a510146102a4578063095ea7b3146102ce5761023a565b3661023a57005b5f5ffd5b348015610249575f5ffd5b50610264600480360381019061025f9190613566565b610993565b6040516102719190613641565b60405180910390f35b348015610285575f5ffd5b5061028e610aae565b60405161029b91906136cb565b60405180910390f35b3480156102af575f5ffd5b506102b8610b3e565b6040516102c59190613703565b60405180910390f35b3480156102d9575f5ffd5b506102f460048036038101906102ef9190613746565b610c97565b6040516103019190613793565b60405180910390f35b348015610315575f5ffd5b5061031e610cb9565b60405161032b9190613807565b60405180910390f35b34801561033f575f5ffd5b50610348610cde565b6040516103559190613703565b60405180910390f35b348015610369575f5ffd5b50610372610ce7565b60405161037f9190613793565b60405180910390f35b348015610393575f5ffd5b506103ae60048036038101906103a99190613820565b610cf9565b6040516103bb9190613793565b60405180910390f35b3480156103cf575f5ffd5b506103d8610d27565b6040516103e59190613641565b60405180910390f35b3480156103f9575f5ffd5b50610402610e22565b60405161040f9190613703565b60405180910390f35b348015610423575f5ffd5b5061042c611045565b604051610439919061388b565b60405180910390f35b61044a61104d565b005b348015610457575f5ffd5b50610472600480360381019061046d9190613746565b611617565b60405161047f9190613703565b60405180910390f35b348015610493575f5ffd5b506104ae60048036038101906104a99190613746565b61163b565b6040516104bb9190613703565b60405180910390f35b3480156104cf575f5ffd5b506104d861165f565b6040516104e591906138c4565b60405180910390f35b3480156104f9575f5ffd5b50610514600480360381019061050f91906138dd565b611684565b6040516105219190613703565b60405180910390f35b348015610535575f5ffd5b5061053e61169d565b60405161054b9190613703565b60405180910390f35b34801561055f575f5ffd5b506105686116f1565b6040516105759190613917565b60405180910390f35b348015610589575f5ffd5b506105a4600480360381019061059f91906138dd565b611715565b6040516105b19190613917565b60405180910390f35b3480156105c5575f5ffd5b506105e060048036038101906105db9190613566565b611750565b6040516105ed9190613703565b60405180910390f35b348015610601575f5ffd5b5061060a611795565b6040516106179190613703565b60405180910390f35b34801561062b575f5ffd5b50610646600480360381019061064191906138dd565b61179b565b6040516106539190613703565b60405180910390f35b61067660048036038101906106719190613930565b6117b4565b005b348015610683575f5ffd5b5061068c611dd9565b005b348015610699575f5ffd5b506106a261229c565b6040516106af9190613703565b60405180910390f35b3480156106c3575f5ffd5b506106cc612308565b6040516106d991906136cb565b60405180910390f35b3480156106ed575f5ffd5b50610708600480360381019061070391906138dd565b612398565b6040516107159190613703565b60405180910390f35b348015610729575f5ffd5b50610744600480360381019061073f9190613746565b6123b1565b6040516107519190613793565b60405180910390f35b348015610765575f5ffd5b50610780600480360381019061077b91906138dd565b6123d3565b60405161078d9190613703565b60405180910390f35b3480156107a1575f5ffd5b506107aa6123ec565b6040516107be989796959493929190613a13565b60405180910390f35b3480156107d2575f5ffd5b506107db612524565b6040516107e89190613703565b60405180910390f35b3480156107fc575f5ffd5b5061080561252a565b6040516108129190613917565b60405180910390f35b348015610826575f5ffd5b50610841600480360381019061083c9190613566565b61254e565b60405161084e9190613793565b60405180910390f35b348015610862575f5ffd5b5061086b61256b565b6040516108789190613917565b60405180910390f35b34801561088c575f5ffd5b5061089561258f565b6040516108a29190613703565b60405180910390f35b3480156108b6575f5ffd5b506108d160048036038101906108cc9190613a9f565b612595565b6040516108de9190613703565b60405180910390f35b3480156108f2575f5ffd5b5061090d600480360381019061090891906138dd565b612617565b60405161091a9190613703565b60405180910390f35b34801561092e575f5ffd5b50610937612630565b60405161094a9796959493929190613add565b60405180910390f35b34801561095e575f5ffd5b5061097960048036038101906109749190613566565b6126d4565b60405161098a959493929190613b50565b60405180910390f35b61099b6134c2565b5f6109a4610d27565b90506109ae6134c2565b5f5f90505b600e811015610aa3578281600e81106109cf576109ce613ba4565b5b60200201518015610a445750602681600e81106109ef576109ee613ba4565b5b015460535f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2082600e8110610a4057610a3f613ba4565b5b0154105b15610a725760018282600e8110610a5e57610a5d613ba4565b5b602002019015159081151581525050610a96565b5f8282600e8110610a8657610a85613ba4565b5b6020020190151590811515815250505b80806001019150506109b3565b508092505050919050565b606060038054610abd90613bfe565b80601f0160208091040260200160405190810160405280929190818152602001828054610ae990613bfe565b8015610b345780601f10610b0b57610100808354040283529160200191610b34565b820191905f5260205f20905b815481529060010190602001808311610b1757829003601f168201915b5050505050905090565b5f60505f9054906101000a900460ff16610b5a575f9050610c94565b5f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610be99190613c42565b905060028173ffffffffffffffffffffffffffffffffffffffff166370a0823160075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401610c479190613917565b602060405180830381865afa158015610c62573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c869190613c81565b610c909190613cd9565b9150505b90565b5f5f610ca1612855565b9050610cae81858561285c565b600191505092915050565b60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f600254905090565b60505f9054906101000a900460ff1681565b5f5f610d03612855565b9050610d1085828561286e565b610d1b858585612901565b60019150509392505050565b610d2f6134c2565b610d376134c2565b5f610d40610e22565b90505f5f90505b600e811015610e19575f600a82600e8110610d6557610d64613ba4565b5b0154600954610d749190613cd9565b9050603482600e8110610d8a57610d89613ba4565b5b0154604283600e8110610da057610d9f613ba4565b5b0154108015610db957508083101580610db857505f82145b5b15610de75760018483600e8110610dd357610dd2613ba4565b5b602002019015159081151581525050610e0b565b5f8483600e8110610dfb57610dfa613ba4565b5b6020020190151590811515815250505b508080600101915050610d47565b50819250505090565b5f5f5f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610e8f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eb39190613d96565b50915091505f826dffffffffffffffffffffffffffff161480610ee557505f816dffffffffffffffffffffffffffff16145b15610ef65760095492505050611042565b3073ffffffffffffffffffffffffffffffffffffffff1660075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f77573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9b9190613c42565b73ffffffffffffffffffffffffffffffffffffffff1603610ffe57816dffffffffffffffffffffffffffff16670de0b6b3a7640000826dffffffffffffffffffffffffffff16610feb9190613cd9565b610ff59190613e13565b92505050611042565b806dffffffffffffffffffffffffffff16670de0b6b3a7640000836dffffffffffffffffffffffffffff166110339190613cd9565b61103d9190613e13565b925050505b90565b5f6012905090565b6110556129f1565b605554483a6110649190613e43565b111561109c576040517ff441e9e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60505f9054906101000a900460ff16156110e2576040517f1ad8494f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f340361111b576040517f19a1bf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60345f600e811061112f5761112e613ba4565b5b015460425f600e811061114557611144613ba4565b5b01541061117e576040517fdf8e376800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60265f600e811061119257611191613ba4565b5b015460535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e81106111e3576111e2613ba4565b5b01541061121c576040517f84dab64600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61122a5f34600954612a37565b90505f670de0b6b3a7640000600954836112449190613cd9565b61124e9190613e13565b90508060545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e81106112a05761129f613ba4565b5b015f8282546112af9190613e76565b9250508190555060525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166113ba57605133908060018154018082558091505060019003905f5260205f20015f9091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b8160425f600e81106113cf576113ce613ba4565b5b015f8282546113de9190613e76565b925050819055508160535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e811061143557611434613ba4565b5b015f8282546114449190613e76565b92505081905550803411156114fa575f81346114609190613e43565b90503373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156114a5573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167fc4e47ebda5850aad45eb70501556332e9d7a5664e604b34512efaee263aa0d468234856040516114f093929190613ea9565b60405180910390a2505b60345f600e811061150e5761150d613ba4565b5b015460425f600e811061152457611523613ba4565b5b01541061153c57611533612b36565b61153b612c54565b5b60345f600e81106115505761154f613ba4565b5b015460425f600e811061156657611565613ba4565b5b0154106115bd575f7f2946ed324b02a3995b07e07216a2f5c83e8dc9e4b52eab07770fdbd1af0ef4cc60425f600e81106115a3576115a2613ba4565b5b0154436040516115b4929190613ede565b60405180910390a25b3373ffffffffffffffffffffffffffffffffffffffff167f3082f48ea05b3fcc96a3f50b9bd103f75800860568f3320fcedeb6de6d0dce21836040516116039190613703565b60405180910390a25050611615612cd2565b565b6053602052815f5260405f2081600e8110611630575f80fd5b015f91509150505481565b6054602052815f5260405f2081600e8110611654575f80fd5b015f91509150505481565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b602681600e8110611693575f80fd5b015f915090505481565b5f60505f9054906101000a900460ff166116b9575f90506116ee565b5f6116c2610e22565b9050670de0b6b3a7640000816116d6610cde565b6116e09190613cd9565b6116ea9190613e13565b9150505b90565b7f000000000000000000000000f08b1fe0cf1210f83a5f8c026c0fd4f717d195fe81565b60518181548110611724575f80fd5b905f5260205f20015f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b60555481565b603481600e81106117aa575f80fd5b015f915090505481565b6117bc6129f1565b605554483a6117cb9190613e43565b1115611803576040517ff441e9e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60505f9054906101000a900460ff16611848576040517fdff61f8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f3403611881576040517f19a1bf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8214806118905750600e8210155b156118c7576040517f4e2a8dfe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064811015611902576040517fabcca32100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603482600e811061191657611915613ba4565b5b0154604283600e811061192c5761192b613ba4565b5b015410611965576040517fdf8e376800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602682600e811061197957611978613ba4565b5b015460535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2083600e81106119ca576119c9613ba4565b5b015410611a03576040517f84dab64600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611a0c610e22565b90505f600a84600e8110611a2357611a22613ba4565b5b0154600954611a329190613cd9565b905080821015611a6e576040517f85fecc1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127108382611a7d9190613cd9565b611a879190613e13565b81611a929190613e76565b821115611acb576040517fe10dffe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611ad7853485612a37565b90505f670de0b6b3a76400008483611aef9190613cd9565b611af99190613e13565b905081611b0530611750565b1015611b3d576040517fe4455cae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b478282612cdc565b81604287600e8110611b5c57611b5b613ba4565b5b015f828254611b6b9190613e76565b925050819055508160535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2087600e8110611bc257611bc1613ba4565b5b015f828254611bd19190613e76565b925050819055508060545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2087600e8110611c2857611c27613ba4565b5b015f828254611c379190613e76565b9250508190555080341115611ced575f8134611c539190613e43565b90503373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611c98573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167fc4e47ebda5850aad45eb70501556332e9d7a5664e604b34512efaee263aa0d46823485604051611ce393929190613ea9565b60405180910390a2505b611cf8303384612901565b603486600e8110611d0c57611d0b613ba4565b5b0154604287600e8110611d2257611d21613ba4565b5b015410611d7957857f2946ed324b02a3995b07e07216a2f5c83e8dc9e4b52eab07770fdbd1af0ef4cc604288600e8110611d5f57611d5e613ba4565b5b015443604051611d70929190613ede565b60405180910390a25b3373ffffffffffffffffffffffffffffffffffffffff167ff3fb67cb71e333dcc656ea2a2a916481a2e5b06ae89e35f667813fc7043e08ad8784604051611dc1929190613ede565b60405180910390a250505050611dd5612cd2565b5050565b611de16129f1565b60505f9054906101000a900460ff1615611e27576040517f1ad8494f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110611e7757611e76613ba4565b5b015490505f8103611eb4576040517fe49c14cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110611f0457611f03613ba4565b5b015490505f60535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110611f5857611f57613ba4565b5b01819055505f60545f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110611fad57611fac613ba4565b5b01819055508160425f600e8110611fc757611fc6613ba4565b5b015f828254611fd69190613e43565b9250508190555060525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16156121fe575f60525f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505f5f90505b6051805490508110156121fc573373ffffffffffffffffffffffffffffffffffffffff16605182815481106120bd576120bc613ba4565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036121ef57605160016051805490506121149190613e43565b8154811061212557612124613ba4565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166051828154811061216157612160613ba4565b5b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060518054806121b8576121b7613f05565b5b600190038181905f5260205f20015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590556121fc565b8080600101915050612085565b505b3373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015612241573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167f35cc6ad8d7e55fcdb00bb23c90df11f0368befe6d3f7e748ee24f5f88810b3e5836040516122889190613703565b60405180910390a2505061229a612cd2565b565b5f60505f9054906101000a900460ff166122b8575f9050612305565b5f6122c1610e22565b90505f6122cd30611750565b6122d5610cde565b6122df9190613e43565b9050670de0b6b3a764000082826122f69190613cd9565b6123009190613e13565b925050505b90565b60606004805461231790613bfe565b80601f016020809104026020016040519081016040528092919081815260200182805461234390613bfe565b801561238e5780601f106123655761010080835404028352916020019161238e565b820191905f5260205f20905b81548152906001019060200180831161237157829003601f168201915b5050505050905090565b600a81600e81106123a7575f80fd5b015f915090505481565b5f5f6123bb612855565b90506123c8818585612901565b600191505092915050565b601881600e81106123e2575f80fd5b015f915090505481565b6060805f5f5f6123fa6134e5565b6124026134e5565b61240a6134e5565b612412610aae565b61241a612308565b612422610cde565b60095460075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600a6026603482600e806020026040519081016040528092919082600e8015612485576020028201915b815481526020019060010190808311612471575b5050505050925081600e806020026040519081016040528092919082600e80156124c4576020028201915b8154815260200190600101908083116124b0575b5050505050915080600e806020026040519081016040528092919082600e8015612503576020028201915b8154815260200190600101908083116124ef575b50505050509050975097509750975097509750975097509091929394959697565b60085481565b7f0000000000000000000000004f8411a4ff4e9ad6905612009cdcb8367602b4fc81565b6052602052805f5260405f205f915054906101000a900460ff1681565b7f000000000000000000000000dfdc2191662fb3a25efa0fea447dccb0db0220ce81565b60095481565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b604281600e8110612626575f80fd5b015f915090505481565b5f6126396134e5565b6126416134c2565b5f5f5f5f60505f9054906101000a900460ff16604261265e610d27565b612666610e22565b61266e61229c565b61267661169d565b61267e610b3e565b85600e806020026040519081016040528092919082600e80156126b6576020028201915b8154815260200190600101908083116126a2575b50505050509550965096509650965096509650965090919293949596565b5f5f6126de6134e5565b6126e66134e5565b6126ee6134c2565b6126f786611750565b60525f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1660535f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060545f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206127c48a610993565b82600e806020026040519081016040528092919082600e80156127fc576020028201915b8154815260200190600101908083116127e8575b5050505050925081600e806020026040519081016040528092919082600e801561283b576020028201915b815481526020019060010190808311612827575b505050505091509450945094509450945091939590929450565b5f33905090565b6128698383836001612f9c565b505050565b5f6128798484612595565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156128fb57818110156128ec578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016128e393929190613f32565b60405180910390fd5b6128fa84848484035f612f9c565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612971575f6040517f96c6fd1e0000000000000000000000000000000000000000000000000000000081526004016129689190613917565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129e1575f6040517fec442f050000000000000000000000000000000000000000000000000000000081526004016129d89190613917565b60405180910390fd5b6129ec83838361316b565b505050565b600260055403612a2d576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600581905550565b5f5f8203612a47575f9050612b2f565b5f82670de0b6b3a764000085612a5d9190613cd9565b612a679190613e13565b90505f60535f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2086600e8110612ab957612ab8613ba4565b5b0154602687600e8110612acf57612ace613ba4565b5b0154612adb9190613e43565b90505f604287600e8110612af257612af1613ba4565b5b0154603488600e8110612b0857612b07613ba4565b5b0154612b149190613e43565b9050612b29612b23848361326f565b8361326f565b93505050505b9392505050565b5f5f90505b605180549050811015612c51575f60518281548110612b5d57612b5c613ba4565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f60535f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110612bd757612bd6613ba4565b5b015490505f811115612c4457612bee308383612901565b5f60535f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f600e8110612c3e57612c3d613ba4565b5b01819055505b8260010192505050612b3b565b50565b5f4703612c8d576040517fbbb20aae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f4790505f60345f600e8110612ca657612ca5613ba4565b5b01549050612cb48183612cdc565b600160505f6101000a81548160ff0219169083151502179055505050565b6001600581905550565b5f61271060085484612cee9190613cd9565b612cf89190613e13565b90505f61271060085484612d0c9190613cd9565b612d169190613e13565b90505f6064604b83612d289190613cd9565b612d329190613e13565b90505f8183612d419190613e43565b90505f8487612d509190613e43565b90505f8487612d5f9190613e43565b90505f6064605f84612d719190613cd9565b612d7b9190613e13565b90505f6064605f84612d8d9190613cd9565b612d979190613e13565b9050612dc53060065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168661285c565b5f861115612e32577f000000000000000000000000dfdc2191662fb3a25efa0fea447dccb0db0220ce73ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015612e30573d5f5f3e3d5ffd5b505b5f851115612e9f577f0000000000000000000000004f8411a4ff4e9ad6905612009cdcb8367602b4fc73ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015612e9d573d5f5f3e3d5ffd5b505b5f881115612ed357612ed2307f000000000000000000000000f08b1fe0cf1210f83a5f8c026c0fd4f717d195fe8a612901565b5b5f84118015612ee157505f83115b15612f905760065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f305d71984308786865f426040518863ffffffff1660e01b8152600401612f4b96959493929190613f67565b60606040518083038185885af1158015612f67573d5f5f3e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190612f8c9190613fc6565b5050505b50505050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361300c575f6040517fe602df050000000000000000000000000000000000000000000000000000000081526004016130039190613917565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361307c575f6040517f94280d620000000000000000000000000000000000000000000000000000000081526004016130739190613917565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508015613165578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161315c9190613703565b60405180910390a35b50505050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480613212575060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1561325f57605554483a6132269190613e43565b111561325e576040517ff441e9e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b61326a838383613285565b505050565b5f61327d828410848461349e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036132d5578060025f8282546132c99190613e76565b925050819055506133a3565b5f5f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490508181101561335e578381836040517fe450d38c00000000000000000000000000000000000000000000000000000000815260040161335593929190613f32565b60405180910390fd5b8181035f5f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036133ea578060025f8282540392505081905550613434565b805f5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516134919190613703565b60405180910390a3505050565b5f6134a8846134b7565b82841802821890509392505050565b5f8115159050919050565b604051806101c00160405280600e90602082028036833780820191505090505090565b604051806101c00160405280600e90602082028036833780820191505090505090565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6135358261350c565b9050919050565b6135458161352b565b811461354f575f5ffd5b50565b5f813590506135608161353c565b92915050565b5f6020828403121561357b5761357a613508565b5b5f61358884828501613552565b91505092915050565b5f600e9050919050565b5f81905092915050565b5f819050919050565b5f8115159050919050565b6135c2816135ae565b82525050565b5f6135d383836135b9565b60208301905092915050565b5f602082019050919050565b6135f481613591565b6135fe818461359b565b9250613609826135a5565b805f5b8381101561363957815161362087826135c8565b965061362b836135df565b92505060018101905061360c565b505050505050565b5f6101c0820190506136555f8301846135eb565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61369d8261365b565b6136a78185613665565b93506136b7818560208601613675565b6136c081613683565b840191505092915050565b5f6020820190508181035f8301526136e38184613693565b905092915050565b5f819050919050565b6136fd816136eb565b82525050565b5f6020820190506137165f8301846136f4565b92915050565b613725816136eb565b811461372f575f5ffd5b50565b5f813590506137408161371c565b92915050565b5f5f6040838503121561375c5761375b613508565b5b5f61376985828601613552565b925050602061377a85828601613732565b9150509250929050565b61378d816135ae565b82525050565b5f6020820190506137a65f830184613784565b92915050565b5f819050919050565b5f6137cf6137ca6137c58461350c565b6137ac565b61350c565b9050919050565b5f6137e0826137b5565b9050919050565b5f6137f1826137d6565b9050919050565b613801816137e7565b82525050565b5f60208201905061381a5f8301846137f8565b92915050565b5f5f5f6060848603121561383757613836613508565b5b5f61384486828701613552565b935050602061385586828701613552565b925050604061386686828701613732565b9150509250925092565b5f60ff82169050919050565b61388581613870565b82525050565b5f60208201905061389e5f83018461387c565b92915050565b5f6138ae826137d6565b9050919050565b6138be816138a4565b82525050565b5f6020820190506138d75f8301846138b5565b92915050565b5f602082840312156138f2576138f1613508565b5b5f6138ff84828501613732565b91505092915050565b6139118161352b565b82525050565b5f60208201905061392a5f830184613908565b92915050565b5f5f6040838503121561394657613945613508565b5b5f61395385828601613732565b925050602061396485828601613732565b9150509250929050565b5f600e9050919050565b5f81905092915050565b5f819050919050565b613994816136eb565b82525050565b5f6139a5838361398b565b60208301905092915050565b5f602082019050919050565b6139c68161396e565b6139d08184613978565b92506139db82613982565b805f5b83811015613a0b5781516139f2878261399a565b96506139fd836139b1565b9250506001810190506139de565b505050505050565b5f6105e0820190508181035f830152613a2c818b613693565b90508181036020830152613a40818a613693565b9050613a4f60408301896136f4565b613a5c60608301886136f4565b613a696080830187613908565b613a7660a08301866139bd565b613a846102608301856139bd565b613a926104208301846139bd565b9998505050505050505050565b5f5f60408385031215613ab557613ab4613508565b5b5f613ac285828601613552565b9250506020613ad385828601613552565b9150509250929050565b5f61042082019050613af15f83018a613784565b613afe60208301896139bd565b613b0c6101e08301886135eb565b613b1a6103a08301876136f4565b613b286103c08301866136f4565b613b366103e08301856136f4565b613b446104008301846136f4565b98975050505050505050565b5f61058082019050613b645f8301886136f4565b613b716020830187613784565b613b7e60408301866139bd565b613b8c6102008301856139bd565b613b9a6103c08301846135eb565b9695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680613c1557607f821691505b602082108103613c2857613c27613bd1565b5b50919050565b5f81519050613c3c8161353c565b92915050565b5f60208284031215613c5757613c56613508565b5b5f613c6484828501613c2e565b91505092915050565b5f81519050613c7b8161371c565b92915050565b5f60208284031215613c9657613c95613508565b5b5f613ca384828501613c6d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f613ce3826136eb565b9150613cee836136eb565b9250828202613cfc816136eb565b91508282048414831517613d1357613d12613cac565b5b5092915050565b5f6dffffffffffffffffffffffffffff82169050919050565b613d3c81613d1a565b8114613d46575f5ffd5b50565b5f81519050613d5781613d33565b92915050565b5f63ffffffff82169050919050565b613d7581613d5d565b8114613d7f575f5ffd5b50565b5f81519050613d9081613d6c565b92915050565b5f5f5f60608486031215613dad57613dac613508565b5b5f613dba86828701613d49565b9350506020613dcb86828701613d49565b9250506040613ddc86828701613d82565b9150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613e1d826136eb565b9150613e28836136eb565b925082613e3857613e37613de6565b5b828204905092915050565b5f613e4d826136eb565b9150613e58836136eb565b9250828203905081811115613e7057613e6f613cac565b5b92915050565b5f613e80826136eb565b9150613e8b836136eb565b9250828201905080821115613ea357613ea2613cac565b5b92915050565b5f606082019050613ebc5f8301866136f4565b613ec960208301856136f4565b613ed660408301846136f4565b949350505050565b5f604082019050613ef15f8301856136f4565b613efe60208301846136f4565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f606082019050613f455f830186613908565b613f5260208301856136f4565b613f5f60408301846136f4565b949350505050565b5f60c082019050613f7a5f830189613908565b613f8760208301886136f4565b613f9460408301876136f4565b613fa160608301866136f4565b613fae6080830185613908565b613fbb60a08301846136f4565b979650505050505050565b5f5f5f60608486031215613fdd57613fdc613508565b5b5f613fea86828701613c6d565b9350506020613ffb86828701613c6d565b925050604061400c86828701613c6d565b915050925092509256fea26469706673582212205df1b214cf8e9a2355c03f81f34f6766998a77b643b3621e03229f0524d8b62064736f6c634300081e0033

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

0000000000000000000000004752ba5dbc23f44d87826276bf6fd6b1c372ad2400000000000000000000000000000000000000000052b7d2dcc80cd2e4000000000000000000000000000000000000000000000000000000061b31ab352c000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000944656570722e66756e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054445455052000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : uniswapV2Router_ (address): 0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24
Arg [1] : totalSupply_ (uint256): 100000000000000000000000000
Arg [2] : ethRaiseinWei_ (uint256): 440000000000000000
Arg [3] : name_ (string): Deepr.fun
Arg [4] : symbol_ (string): DEEPR

-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 0000000000000000000000004752ba5dbc23f44d87826276bf6fd6b1c372ad24
Arg [1] : 00000000000000000000000000000000000000000052b7d2dcc80cd2e4000000
Arg [2] : 000000000000000000000000000000000000000000000000061b31ab352c0000
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [6] : 44656570722e66756e0000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [8] : 4445455052000000000000000000000000000000000000000000000000000000


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.