ETH Price: $3,056.28 (+1.36%)
Gas: 3 Gwei

Token

Kanpai (KPAI)
 

Overview

Max Total Supply

10,000,000 KPAI

Holders

309

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Filtered by Token Holder
kevinsailly.eth
Balance
961.90989206994820791 KPAI

Value
$0.00
0x3af9be25028cdf4517ed28943ea3542a670ced17
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
Kanpai

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2024-01-12
*/

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;

// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

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

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

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

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

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

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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);
}

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 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);
}

// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 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 ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-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 ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 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);
}

/**
 * @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 ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 */
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}.
     *
     * All two of these 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}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * 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:
     * ```
     * 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);
            }
        }
    }
}

// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

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

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

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

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

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

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys a `value` amount of tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 value) public virtual {
        _burn(_msgSender(), value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, deducting from
     * the caller's allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `value`.
     */
    function burnFrom(address account, uint256 value) public virtual {
        _spendAllowance(account, _msgSender(), value);
        _burn(account, value);
    }
}

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

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

// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

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;
}

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;
}

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);
}

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;
}

pragma abicoder v2;

/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
    /// @dev In the implementation you must pay the pool tokens owed for the swap.
    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external;
}

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}

/// @title ERC20 rewards
/// @author @niera26
/// @notice buy and sell tax on this token with rewardToken as rewards
/// @notice source: https://github.com/niera26/erc20-rewards-contracts
contract ERC20Rewards is Ownable, ERC20, ERC20Burnable, ReentrancyGuard {
    using SafeERC20 for IERC20;
    using SafeERC20 for IERC20Metadata;
    using EnumerableSet for EnumerableSet.AddressSet;

    // =========================================================================
    // dependencies.
    // =========================================================================

    ISwapRouter public constant swapRouter = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
    IUniswapV2Router02 public constant router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
    IERC20Metadata public constant rewardToken = IERC20Metadata(0x6De037ef9aD2725EB40118Bb1702EBb27e4Aeb24); // RNDR

    // the amm pair where the tranfers from/to are taxed.
    // (populated with WETH/this token pair address in the constructor).
    IUniswapV2Pair public immutable pair;

    // =========================================================================
    // rewards management.
    // =========================================================================

    struct Share {
        uint256 amount; // recorded balance after last transfer.
        uint256 earned; // amount of tokens earned but not claimed yet.
        uint256 tokenPerShareLast; // token per share value of the last earn occurrence.
    }

    // numerator multiplier so tokenPerShare does not get rounded to 0.
    uint256 private constant PRECISION = 1e18;

    // scale factor so reward token scales to 18 decimals.
    uint256 private immutable SCALE_FACTOR;

    // total shares of this token.
    // (different from total supply because of addresses excluded from rewards).
    uint256 public totalShares;

    // shareholders record.
    // (addresses included to rewards are updated every time they send/receive tokens).
    mapping(address => Share) private shareholders;

    // the accumulated amount of reward token per share.
    uint256 private tokenPerShare;

    // total amount of reward tokens ever claimed.
    uint256 public totalRewardClaimed;

    // total amount of reward tokens ever distributed.
    uint256 public totalRewardDistributed;

    // contract addresses that opted in for rewards.
    mapping(address => bool) public isOptin;

    // =========================================================================
    // reward donations.
    // =========================================================================

    // the number of reward tokens to emit per block.
    uint256 public rewardTokenPerBlock;

    // the amount of reward tokens emitted on last emitting block update.
    uint256 public emittedRewardsCache;

    // last block reward tokens has been emitted.
    uint256 public lastEmittingBlock;

    // =========================================================================
    // operator address.
    // =========================================================================

    // the operator address receive marketing tax and can set non critical
    // settings. Allows to renounce ownership so critical settings can't be
    // updated anymore. It is the same as the owner by default and receive the
    // marketing tax. It can:
    // - update itself.
    // - remove max wallet limits.
    // - set uniswap V3 pool fee setting.
    // - set the reward token per block rate.
    address public operator;

    // =========================================================================
    // anti-bot and limitations.
    // =========================================================================

    EnumerableSet.AddressSet private blacklist;

    uint256 public maxWallet = type(uint256).max; // set to 1% in initialize
    uint256 public startBlock = 0;
    uint8 public deadBlocks = 1;

    // =========================================================================
    // pool options.
    // =========================================================================

    uint24 public poolFee = 10000; // works for RNDR

    // =========================================================================
    // fees.
    // =========================================================================

    uint24 public constant maxSwapFee = 3000;
    uint24 public constant maxMarketingFee = 10000;
    uint24 public constant feeDenominator = 10000;

    uint24 public buyFee = 2400;
    uint24 public sellFee = 2400;
    uint24 public marketingFee = 10000;

    // =========================================================================
    // events.
    // =========================================================================

    event OptIn(address addr);
    event OptOut(address addr);
    event AddToBlacklist(address addr);
    event RemoveFromBlacklist(address addr);
    event Claim(address indexed addr, address indexed to, uint256 amount);
    event Distribute(address indexed addr, uint256 amount);
    event Sweep(address indexed addr, address indexed token, uint256 amount);

    // =========================================================================
    // modifiers.
    // =========================================================================

    modifier onlyOperator() {
        require(msg.sender == operator, "!operator");
        _;
    }

    // =========================================================================
    // constructor.
    // =========================================================================

    constructor(string memory name, string memory symbol, uint256 _totalSupply)
        Ownable(msg.sender)
        ERC20(name, symbol)
    {
        // operator is deployer by default.
        operator = msg.sender;

        // set the reward token scale factor.
        uint8 rewardTokenDecimals = rewardToken.decimals();

        require(rewardTokenDecimals <= 18, "reward token decimals must be <= 18");

        SCALE_FACTOR = 10 ** (18 - rewardTokenDecimals);

        // create an amm pair with WETH.
        // as a contract, pair is automatically excluded from rewards.
        IUniswapV2Factory factory = IUniswapV2Factory(router.factory());

        pair = IUniswapV2Pair(factory.createPair(router.WETH(), address(this)));

        // mint total supply to itself.
        _mint(address(this), _totalSupply * 10 ** decimals());
    }

    // =========================================================================
    // exposed contract values.
    // =========================================================================

    /**
     * Whether the given address is blacklisted or not.
     *
     * The only way an address can be blacklisted is by receiving tokens when
     * trading is not enabled.
     */
    function isBlacklisted(address addr) public view returns (bool) {
        return blacklist.contains(addr);
    }

    /**
     * The circulating supply.
     *
     * It is the total supply minus the balances of all blacklisted addresses.
     *
     * Very gas intensive, should not be used in a state modifying function.
     */
    function circulatingSupply() public view returns (uint256) {
        uint256 lockedSupply;
        uint256 length = blacklist.length();

        for (uint256 i = 0; i < length; i++) {
            lockedSupply += super.balanceOf(blacklist.at(i));
        }

        return totalSupply() - lockedSupply;
    }

    /**
     * Balance of the given account.
     *
     * 0 when trading is enabled and the account is blacklisted.
     */
    function balanceOf(address account) public view override returns (uint256) {
        if (!isBlacklisted(account) || !_isTradingEnabled()) {
            return super.balanceOf(account);
        }

        return 0;
    }

    /**
     * Locked balance of the given account.
     *
     * 0 when the the account is not blacklisted.
     */
    function lockedBalanceOf(address account) public view returns (uint256) {
        if (isBlacklisted(account)) {
            return super.balanceOf(account);
        }

        return 0;
    }

    /**
     * The remaining rewards to emit.
     */
    function remainingRewards() public view returns (uint256) {
        return rewardBalance() - emittedRewards();
    }

    /**
     * The reward balance (amount that can be emitted in total).
     *
     * It is this contract balance of reward tokens minus the amount remaining
     * to claim.
     */
    function rewardBalance() public view returns (uint256) {
        uint256 amountToClaim = totalRewardDistributed - totalRewardClaimed;

        return rewardToken.balanceOf(address(this)) - amountToClaim;
    }

    /**
     * The amount of reward emitted since the last emitting block recorded,
     * according to the reward token per block.
     *
     * Emitting block is recorded when setting the reward tokens per block and
     * during an distribution occurrence.
     *
     * This value is capped by the reward balance.
     */
    function emittedRewards() public view returns (uint256) {
        if (lastEmittingBlock == 0) return 0;
        if (rewardTokenPerBlock == 0) return 0;

        uint256 balance = rewardBalance();

        if (balance == 0) return 0;

        uint256 emitted = emittedRewardsCache + (rewardTokenPerBlock * (block.number - lastEmittingBlock));

        return emitted < balance ? emitted : balance;
    }

    /**
     * The amount of reward tokens the given address can claim.
     */
    function pendingRewards(address addr) external view returns (uint256) {
        return _pendingRewards(shareholders[addr]);
    }

    // =========================================================================
    // exposed user functions.
    // =========================================================================

    /**
     * Claim reward tokens and send them to given address.
     */
    function claim(address to) external nonReentrant {
        Share storage share = shareholders[msg.sender];

        _earn(share);

        uint256 amountToClaim = share.earned;

        if (amountToClaim == 0) return;

        share.earned = 0;

        totalRewardClaimed += amountToClaim;

        rewardToken.safeTransfer(to, amountToClaim);

        emit Claim(msg.sender, to, amountToClaim);
    }

    /**
     * Optin for rewards when you are excluded from rewards (contracts).
     */
    function rewardOptin() external {
        _includeToRewards(msg.sender);

        isOptin[msg.sender] = true;

        emit OptIn(msg.sender);
    }

    /**
     * Optout for rewards when you are included to rewards (contracts).
     */
    function rewardOptout() external {
        _removeFromRewards(msg.sender);

        isOptin[msg.sender] = false;

        emit OptOut(msg.sender);
    }

    /**
     * Swap the collected tax to ETH.
     *
     * Pass minimal expected amount to prevent slippage/frontrun.
     */
    function swapCollectedTax(uint256 amountOutMin) public {
        // return if no tax collected.
        uint256 amountIn = balanceOf(address(this));

        if (amountIn == 0) return;

        // swap tax to eth.
        uint256 collectedEth = _swapTokenToETHV2(address(this), amountIn, amountOutMin);

        // collect marketing tax.
        uint256 marketingAmount = (collectedEth * marketingFee) / feeDenominator;

        if (marketingAmount > 0) {
            payable(operator).transfer(marketingAmount);
        }
    }

    /**
     * Distribute reward token.
     *
     * Pass minimal expected amount to prevent slippage/frontrun.
     */
    function distribute(uint256 amountOutMinimum) public {
        if (totalShares == 0) return;

        // distribute the rewards that was emitted since last update.
        uint256 amountToDistribute = emittedRewards();

        // swap eth balance to reward token and add it to amount to distribute.
        uint256 amountIn = address(this).balance;

        if (amountIn > 0) {
            amountToDistribute += _swapETHToRewardV3(address(this), amountIn, amountOutMinimum);
        }

        // stop when no rewards.
        if (amountToDistribute == 0) return;

        // distribute rewards.
        tokenPerShare += (amountToDistribute * SCALE_FACTOR * PRECISION) / totalShares;
        totalRewardDistributed += amountToDistribute;

        // reset emitted rewards.
        emittedRewardsCache = 0;
        lastEmittingBlock = block.number;

        emit Distribute(msg.sender, amountToDistribute);
    }

    /**
     * Sweep any other ERC20 mistakenly sent to this contract.
     */
    function sweep(IERC20 otherToken) external {
        require(address(otherToken) != address(this), "!sweep");
        require(address(otherToken) != address(rewardToken), "!sweep");

        uint256 amount = otherToken.balanceOf(address(this));

        otherToken.safeTransfer(msg.sender, amount);

        emit Sweep(msg.sender, address(otherToken), amount);
    }

    // =========================================================================
    // exposed admin functions.
    // =========================================================================

    /**
     * Send initial allocations before liquidity is initialized.
     */
    function allocate(address to, uint256 amount) external onlyOwner {
        require(startBlock == 0, "!initialized");

        this.transfer(to, amount);
    }

    /**
     * Set the fees.
     */
    function setFee(uint24 _buyFee, uint24 _sellFee, uint24 _marketingFee) external onlyOwner {
        require(_buyFee <= maxSwapFee, "!buyFee");
        require(_sellFee <= maxSwapFee, "!sellFee");
        require(_marketingFee <= maxMarketingFee, "!marketingFee");

        buyFee = _buyFee;
        sellFee = _sellFee;
        marketingFee = _marketingFee;
    }

    /**
     * Remove the given address from the blacklist.
     */
    function removeFromBlacklist(address addr) external onlyOwner {
        _removeFromBlacklist(addr);
    }

    /**
     * Initialize the trading with the given eth and this contract balance.
     *
     * Starts trading, sets max wallet to 1% of the supply, create the uniswap V2 pair
     * with ETH, adds liquidity.
     *
     * LP tokens are sent to owner.
     */
    function initialize() external payable onlyOwner {
        require(msg.value > 0, "!liquidity");
        require(startBlock == 0, "!initialized");

        // start deadblocks from there.
        startBlock = block.number;

        // init max wallet to 1%.
        maxWallet = totalSupply() / 100;

        // the all balance will be put in the LP.
        uint256 balance = balanceOf(address(this));

        // approve router to use total balance.
        _approve(address(this), address(router), balance);

        // add liquidity and send LP to owner.
        router.addLiquidityETH{value: msg.value}(address(this), balance, 0, 0, msg.sender, block.timestamp);
    }

    // =========================================================================
    // exposed operator functions.
    // =========================================================================

    /**
     * Operator can update itself.
     */
    function setOperator(address _operator) external onlyOperator {
        require(address(0) != _operator, "!address");
        operator = _operator;
    }

    /**
     * Remove max wallet limits, one shoot.
     */
    function removeMaxWallet() external onlyOperator {
        maxWallet = type(uint256).max;
    }

    /**
     * Set the uniswap V3 pool fee.
     */
    function setPoolFee(uint24 _poolFee) external onlyOperator {
        poolFee = _poolFee;
    }

    /**
     * Set the reward token per block. Accumulates the emitted rewards until this
     * block before updating the value.
     */
    function setRewardTokenPerBlock(uint256 _rewardTokenPerBlock) external onlyOperator {
        emittedRewardsCache = emittedRewards();
        rewardTokenPerBlock = _rewardTokenPerBlock;
        lastEmittingBlock = block.number;
    }

    /**
     * Set the reward token per block without accumulating what has been
     * emitted. Fallback is case of an error.
     */
    function setRewardTokenPerBlockUnsafe(uint256 _rewardTokenPerBlock) external onlyOperator {
        rewardTokenPerBlock = _rewardTokenPerBlock;
    }

    /**
     * Empty the emitted rewards. Fallback in case of error.
     */
    function resetEmittedRewardsUnsafe() external onlyOperator {
        emittedRewardsCache = 0;
    }

    // =========================================================================
    // internal functions.
    // =========================================================================

    /**
     * Whether the trading is enabled or not.
     */
    function _isTradingEnabled() private view returns (bool) {
        return block.number > startBlock + deadBlocks;
    }

    /**
     * Whether the given address can be blacklisted.
     *
     * Obviously this contract, the router and the pair can't be blacklisted.
     */
    function _isExcludedFromBlacklist(address addr) private view returns (bool) {
        return address(this) == addr || address(router) == addr || address(pair) == addr;
    }

    /**
     * Whether the given address is excluded from max wallet limit.
     *
     * Blacklisted addresses are excluded too so they can buy as much as they want.
     */
    function _isExcludedFromMaxWallet(address addr) private view returns (bool) {
        return address(this) == addr || address(router) == addr || address(pair) == addr || isBlacklisted(addr);
    }

    /**
     * Whether the given adress is excluded from taxes.
     */
    function _isExcludedFromTaxes(address addr) private view returns (bool) {
        return address(this) == addr || address(router) == addr;
    }

    /**
     * Whether the given address is excluded from rewards.
     *
     * - blacklisted addresses.
     * - addresses of contracts that didn't opted in for rewards.
     * - zero address to save gas on mint/burn (its balance is always 0 so it would never get shares anyway).
     * - this contract address is removed too because address(this).code.length == 0 in the constructor.
     * - remove dead address because people are used to it.
     */
    function _isExcludedFromRewards(address addr) private view returns (bool) {
        return address(0) == addr || address(this) == addr || (addr.code.length > 0 && !isOptin[addr])
            || isBlacklisted(addr) || 0x000000000000000000000000000000000000dEaD == addr;
    }

    /**
     * Add the given address to blacklist.
     */
    function _addToBlacklist(address addr) private {
        _removeFromRewards(addr);

        blacklist.add(addr);

        emit AddToBlacklist(addr);
    }

    /**
     * Remove the given address from blacklist.
     */
    function _removeFromBlacklist(address addr) private {
        _includeToRewards(addr);

        blacklist.remove(addr);

        emit RemoveFromBlacklist(addr);
    }

    /**
     * Include the given address to rewards. Should only concern:
     *
     * - addresses of contracts opting in for rewards.
     * - addresses being removed from blacklist.
     */
    function _includeToRewards(address addr) private {
        // ensure we dont update total shares twice.
        if (!_isExcludedFromRewards(addr)) return;

        // update total shares.
        uint256 balance = super.balanceOf(addr);

        totalShares += balance;

        // restart earning from now.
        Share storage share = shareholders[addr];

        share.amount = balance;
        share.tokenPerShareLast = tokenPerShare;
    }

    /**
     * Remove the given address from rewards. Should only concern:
     *
     * - addresses of contracts opting out of rewards.
     * - addresses being added to blacklist.
     */
    function _removeFromRewards(address addr) private {
        // ensure we dont update total shares twice.
        if (_isExcludedFromRewards(addr)) return;

        // update total shares.
        totalShares -= super.balanceOf(addr);

        // make sure pending rewards are earned and stop earning (share.amount = 0)
        Share storage share = shareholders[addr];

        _earn(share);

        share.amount = 0;
    }

    /**
     * The pending rewards of the given share.
     *
     * The rewards earned since the last transfer are added to the already earned
     * rewards.
     */
    function _pendingRewards(Share memory share) private view returns (uint256) {
        uint256 RDiff = tokenPerShare - share.tokenPerShareLast;
        uint256 earned = (share.amount * RDiff) / (SCALE_FACTOR * PRECISION);

        return share.earned + earned;
    }

    /**
     * Earn the rewards of the given share.
     */
    function _earn(Share storage share) private {
        uint256 pending = _pendingRewards(share);

        share.earned = pending;
        share.tokenPerShareLast = tokenPerShare;
    }

    /**
     * Override the update method in order to take fee when the transfer is from/to
     * a registered amm pair.
     *
     * - transfers from a blacklisted address reverts.
     * - transfers from/to the amm pair are taxed.
     * - taxed tokens are sent to this very contract.
     * - on a taxed sell, the collected tax is swapped for eth.
     * - updates the shares of both the from and to addresses.
     * - addresses buying when trading is not enabled are blacklisted.
     * - prevents receiving address to get more than max wallet.
     */
    function _update(address from, address to, uint256 amount) internal override {
        // check if trading is enabled.
        bool isTradingEnabled = _isTradingEnabled();

        // check if it is a taxed buy/sell.
        bool isTaxedBuy = address(pair) == from && !_isExcludedFromTaxes(to);
        bool isTaxedSell = !_isExcludedFromTaxes(from) && address(pair) == to;

        // lock the blacklisted senders when trading is enabled.
        if (isTradingEnabled && isBlacklisted(from)) {
            revert("locked");
        }

        // compute the fee of a taxed buy/sell.
        uint256 fee = (isTaxedBuy ? buyFee : 0) + (isTaxedSell ? sellFee : 0);

        uint256 taxAmount = (amount * fee) / feeDenominator;

        uint256 actualTransferAmount = amount - taxAmount;

        // transfer the tax to this contract.
        if (taxAmount > 0) {
            super._update(from, address(this), taxAmount);
        }

        // swaps the tax to eth when it is a sell.
        if (isTaxedSell) {
            swapCollectedTax(0);
        }

        // transfer the actual amount to receiving address.
        super._update(from, to, actualTransferAmount);

        // update shares of sending an receiving addresses.
        _updateShare(from);
        _updateShare(to);

        // any receiving address should be blacklisted when trading is not enabled.
        if (!isTradingEnabled && !_isExcludedFromBlacklist(to)) {
            _addToBlacklist(to);
        }

        // revert when the receiving address balance is above max wallet.
        if (!_isExcludedFromMaxWallet(to)) {
            require(balanceOf(to) <= maxWallet, "!maxWallet");
        }
    }

    /**
     * Update the total shares and the shares of the given address if it is not
     * excluded from rewards.
     *
     * Earn first with his current share amount then update shares according to
     * its new balance.
     */
    function _updateShare(address addr) private {
        if (_isExcludedFromRewards(addr)) return;

        uint256 balance = balanceOf(addr);

        Share storage share = shareholders[addr];

        totalShares = totalShares - share.amount + balance;

        _earn(share);

        share.amount = balance;
    }

    /**
     * Swap amount of this token for ETH to address and return the amount received.
     */
    function _swapTokenToETHV2(address to, uint256 amountIn, uint256 amountOutMin) private returns (uint256) {
        // return 0 if no amount given.
        if (amountIn == 0) return 0;

        // approve router to spend tokens.
        _approve(address(this), address(router), amountIn);

        // swap the whole amount to eth.
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = router.WETH();

        uint256 originalETHbalance = address(this).balance;

        router.swapExactTokensForETHSupportingFeeOnTransferTokens(amountIn, amountOutMin, path, to, block.timestamp);

        return address(this).balance - originalETHbalance;
    }

    /**
     * Swap amount of ETH for reward tokens to address and return the amount received.
     */
    function _swapETHToRewardV3(address to, uint256 amountIn, uint256 amountOutMinimum) private returns (uint256) {
        // return 0 if no amount given.
        if (amountIn == 0) return 0;

        // build the swap parameter.
        ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
            tokenIn: router.WETH(),
            tokenOut: address(rewardToken),
            fee: poolFee,
            recipient: to,
            deadline: block.timestamp,
            amountIn: amountIn,
            amountOutMinimum: amountOutMinimum,
            sqrtPriceLimitX96: 0
        });

        // execute the swap and return the number of received tokens.
        return swapRouter.exactInputSingle{value: amountIn}(params);
    }

    receive() external payable {}
}

/// @title Kanpai
/// @author @niera26
/// @notice buy and sell tax on this token with RNDR as rewards
/// @notice source: https://github.com/kanpairender/kanpai-contracts
contract Kanpai is ERC20Rewards {
    constructor() ERC20Rewards("Kanpai", "KPAI", 10e6) {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"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":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"AddToBlacklist","type":"event"},{"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":"addr","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Distribute","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"OptIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"OptOut","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"RemoveFromBlacklist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Sweep","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":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"allocate","outputs":[],"stateMutability":"nonpayable","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":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"circulatingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deadBlocks","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"name":"distribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emittedRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emittedRewardsCache","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDenominator","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isOptin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastEmittingBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketingFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMarketingFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSwapFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"remainingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"removeFromBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeMaxWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetEmittedRewardsUnsafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardOptin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardOptout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardTokenPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sellFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"_buyFee","type":"uint24"},{"internalType":"uint24","name":"_sellFee","type":"uint24"},{"internalType":"uint24","name":"_marketingFee","type":"uint24"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_poolFee","type":"uint24"}],"name":"setPoolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardTokenPerBlock","type":"uint256"}],"name":"setRewardTokenPerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardTokenPerBlock","type":"uint256"}],"name":"setRewardTokenPerBlockUnsafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapCollectedTax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"otherToken","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardDistributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"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":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040526000196013556000601455601580546001600160681b0319166b2710000960000960002710011790553480156200003a57600080fd5b5060408051808201825260068152654b616e70616960d01b602080830191909152825180840190935260048352634b50414960e01b90830152906298968082823380620000a257604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000ad816200038f565b506004620000bc838262000fb9565b506005620000cb828262000fb9565b5050600160065550601080546001600160a01b031916331790556040805163313ce56760e01b81529051600091736de037ef9ad2725eb40118bb1702ebb27e4aeb249163313ce567916004808201926020929091908290030181865afa1580156200013a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000160919062001085565b905060128160ff161115620001c45760405162461bcd60e51b815260206004820152602360248201527f72657761726420746f6b656e20646563696d616c73206d757374206265203c3d60448201526204062760eb1b606482015260840162000099565b620001d1816012620010c0565b620001de90600a620011d9565b60a081815250506000600080516020620040eb8339815191526001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200025b9190620011ea565b9050806001600160a01b031663c9c65396600080516020620040eb8339815191526001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002ba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002e09190620011ea565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201523060248201526044016020604051808303816000875af11580156200032d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003539190620011ea565b6001600160a01b03166080526200038430620003726012600a620011d9565b6200037e908662001215565b620003df565b50505050506200132f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0382166200040b5760405163ec442f0560e01b81526000600482015260240162000099565b62000419600083836200041d565b5050565b60006200042962000634565b90506000846001600160a01b03166080516001600160a01b0316148015620004595750620004578462000655565b155b90506000620004688662000655565b158015620004895750846001600160a01b03166080516001600160a01b0316145b90508280156200049f57506200049f866200068c565b15620004d75760405162461bcd60e51b81526020600482015260066024820152651b1bd8dad95960d21b604482015260640162000099565b600081620004e7576000620004fb565b601554670100000000000000900462ffffff165b83620005095760006200051a565b601554640100000000900462ffffff165b6200052691906200122f565b62ffffff16905060006127106200053e838862001215565b6200054a919062001255565b905060006200055a828862001278565b905081156200057057620005708930846200069b565b83156200058357620005836000620007ce565b620005908989836200069b565b6200059b896200087d565b620005a6886200087d565b85158015620005bd5750620005bb88620008eb565b155b15620005ce57620005ce8862000938565b620005d98862000990565b6200062957601354620005ec89620009f2565b1115620006295760405162461bcd60e51b815260206004820152600a602482015269085b585e15d85b1b195d60b21b604482015260640162000099565b505050505050505050565b6015546014546000916200064e9160ff909116906200128e565b4311905090565b6000306001600160a01b0383161480620006865750600080516020620040eb8339815191526001600160a01b038316145b92915050565b60006200068660118362000a40565b6001600160a01b038316620006ca578060036000828254620006be91906200128e565b909155506200073e9050565b6001600160a01b038316600090815260016020526040902054818110156200071f5760405163391434e360e21b81526001600160a01b0385166004820152602481018290526044810183905260640162000099565b6001600160a01b03841660009081526001602052604090209082900390555b6001600160a01b0382166200075c576003805482900390556200077b565b6001600160a01b03821660009081526001602052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051620007c191815260200190565b60405180910390a3505050565b6000620007db30620009f2565b905080600003620007ea575050565b6000620007f930838562000a65565b6015549091506000906127109062000825906a0100000000000000000000900462ffffff168462001215565b62000831919062001255565b9050801562000877576010546040516001600160a01b039091169082156108fc029083906000818181858888f1935050505015801562000875573d6000803e3d6000fd5b505b50505050565b620008888162000c19565b15620008915750565b60006200089e82620009f2565b6001600160a01b0383166000908152600860205260409020805460075492935090918391620008cd9162001278565b620008d991906200128e565b600755620008e78162000c9f565b5550565b6000306001600160a01b03831614806200091c5750600080516020620040eb8339815191526001600160a01b038316145b80620006865750506080516001600160a01b0390811691161490565b620009438162000ce2565b6200095060118262000d51565b506040516001600160a01b03821681527f6b713f4f12b0a0860e4b6b54d27ef8de95da632b1250f5c12f8254fdedbc2ebd9060200160405180910390a150565b6000306001600160a01b0383161480620009c15750600080516020620040eb8339815191526001600160a01b038316145b80620009e05750816001600160a01b03166080516001600160a01b0316145b8062000686575062000686826200068c565b6000620009ff826200068c565b158062000a13575062000a1162000634565b155b1562000a38576001600160a01b03821660009081526001602052604090205462000686565b506000919050565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b60008260000362000a795750600062000a5e565b62000a9530600080516020620040eb8339815191528562000d68565b604080516002808252606082018352600092602083019080368337019050509050308160008151811062000acd5762000acd620012a4565b60200260200101906001600160a01b031690816001600160a01b031681525050600080516020620040eb8339815191526001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000b3b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000b619190620011ea565b8160018151811062000b775762000b77620012a4565b6001600160a01b039092166020928302919091019091015260405163791ac94760e01b81524790600080516020620040eb8339815191529063791ac9479062000bcd908890889087908c904290600401620012ba565b600060405180830381600087803b15801562000be857600080fd5b505af115801562000bfd573d6000803e3d6000fd5b50505050804762000c0f919062001278565b9695505050505050565b60006001600160a01b038216158062000c3a5750306001600160a01b038316145b8062000c7557506000826001600160a01b03163b11801562000c7557506001600160a01b0382166000908152600c602052604090205460ff16155b8062000c87575062000c87826200068c565b80620006865750506001600160a01b031661dead1490565b60408051606081018252825481526001830154602082015260028301549181019190915260009062000cd19062000d7c565b600183015550600954600290910155565b62000ced8162000c19565b1562000cf65750565b6001600160a01b0381166000908152600160205260409020546007600082825462000d22919062001278565b90915550506001600160a01b038116600090815260086020526040902062000d4a8162000c9f565b6000905550565b600062000a5e836001600160a01b03841662000de6565b62000d77838383600162000e38565b505050565b600080826040015160095462000d93919062001278565b90506000670de0b6b3a764000060a05162000daf919062001215565b845162000dbe90849062001215565b62000dca919062001255565b905080846020015162000dde91906200128e565b949350505050565b600081815260018301602052604081205462000e2f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000686565b50600062000686565b6001600160a01b03841662000e645760405163e602df0560e01b81526000600482015260240162000099565b6001600160a01b03831662000e9057604051634a1406b160e11b81526000600482015260240162000099565b6001600160a01b03808516600090815260026020908152604080832093871683529290522082905580156200087757826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405162000f0591815260200190565b60405180910390a350505050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168062000f3e57607f821691505b60208210810362000f5f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000d77576000816000526020600020601f850160051c8101602086101562000f905750805b601f850160051c820191505b8181101562000fb15782815560010162000f9c565b505050505050565b81516001600160401b0381111562000fd55762000fd562000f13565b62000fed8162000fe6845462000f29565b8462000f65565b602080601f8311600181146200102557600084156200100c5750858301515b600019600386901b1c1916600185901b17855562000fb1565b600085815260208120601f198616915b82811015620010565788860151825594840194600190910190840162001035565b5085821015620010755787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200109857600080fd5b815160ff8116811462000a5e57600080fd5b634e487b7160e01b600052601160045260246000fd5b60ff8281168282160390811115620006865762000686620010aa565b600181815b808511156200111d578160001904821115620011015762001101620010aa565b808516156200110f57918102915b93841c9390800290620010e1565b509250929050565b600082620011365750600162000686565b81620011455750600062000686565b81600181146200115e5760028114620011695762001189565b600191505062000686565b60ff8411156200117d576200117d620010aa565b50506001821b62000686565b5060208310610133831016604e8410600b8410161715620011ae575081810a62000686565b620011ba8383620010dc565b8060001904821115620011d157620011d1620010aa565b029392505050565b600062000a5e60ff84168362001125565b600060208284031215620011fd57600080fd5b81516001600160a01b038116811462000a5e57600080fd5b8082028115828204841417620006865762000686620010aa565b62ffffff8181168382160190808211156200124e576200124e620010aa565b5092915050565b6000826200127357634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115620006865762000686620010aa565b80820180821115620006865762000686620010aa565b634e487b7160e01b600052603260045260246000fd5b600060a08201878352602087602085015260a0604085015281875180845260c08601915060208901935060005b818110156200130e5784516001600160a01b031683529383019391830191600101620012e7565b50506001600160a01b03969096166060850152505050608001529392505050565b60805160a051612d73620013786000396000818161115101526119b20152600081816107f80152818161210b01528181612167015281816125dc01526126a10152612d736000f3fe6080604052600436106103905760003560e01c806373dd250c116101dc578063c31c9c0711610102578063e7e3a24d116100a0578063f887ea401161006f578063f887ea4014610a29578063f8b45b0514610a51578063fabb0b4f14610a67578063fe575a8714610a8157600080fd5b8063e7e3a24d1461099c578063e7e82b69146109b1578063f2fde38b146109e1578063f7c618c114610a0157600080fd5b8063d7406965116100dc578063d740696514610901578063dbfa0bb514610921578063dc07b61714610941578063dd62ed3e1461095657600080fd5b8063c31c9c07146108a4578063c38ed941146108cc578063cebd7ae8146108ec57600080fd5b80639358928b1161017a578063aa5c3ab411610149578063aa5c3ab41461083a578063afb62e561461084f578063b3ab15fb14610864578063b78b52df1461088457600080fd5b80639358928b146107bc57806395d89b41146107d1578063a8aa1b31146107e6578063a9059cbb1461081a57600080fd5b80638da5cb5b116101b65780638da5cb5b14610754578063909921c71461077257806391c05b0b146107875780639266cc2a146107a757600080fd5b806373dd250c1461070c57806379cc67901461072c5780638129fc1c1461074c57600080fd5b80633a98ef39116102c1578063570ca7351161025f5780636b67c4df1161022e5780636b67c4df1461069e5780636f83f6a2146106c157806370a08231146106d7578063715018a6146106f757600080fd5b8063570ca7351461061057806359303a1114610648578063593557361461066857806366edecce1461068857600080fd5b806348cd4cb11161029b57806348cd4cb1146105ae578063537df3b6146105c45780635428c9cb146105e4578063554c798a146105fa57600080fd5b80633a98ef391461055457806342966c681461056a578063470624021461058a57600080fd5b80631e83409a1161032e5780632b14ca56116103085780632b14ca56146104d957806330188ee8146104fc578063313ce5671461051257806331d7a2621461053457600080fd5b80631e83409a146104835780632251c730146104a357806323b872dd146104b957600080fd5b806309094d661161036a57806309094d661461041e578063095ea7b314610434578063180b0d7e1461041e57806318160ddd1461046457600080fd5b806301681a621461039c57806306fdde03146103be578063089fe6aa146103e957600080fd5b3661039757005b600080fd5b3480156103a857600080fd5b506103bc6103b7366004612965565b610aa1565b005b3480156103ca57600080fd5b506103d3610c02565b6040516103e091906129a6565b60405180910390f35b3480156103f557600080fd5b5060155461040a90610100900462ffffff1681565b60405162ffffff90911681526020016103e0565b34801561042a57600080fd5b5061040a61271081565b34801561044057600080fd5b5061045461044f3660046129d9565b610c94565b60405190151581526020016103e0565b34801561047057600080fd5b506003545b6040519081526020016103e0565b34801561048f57600080fd5b506103bc61049e366004612965565b610cae565b3480156104af57600080fd5b50610475600f5481565b3480156104c557600080fd5b506104546104d4366004612a05565b610d74565b3480156104e557600080fd5b5060155461040a90600160381b900462ffffff1681565b34801561050857600080fd5b50610475600b5481565b34801561051e57600080fd5b5060125b60405160ff90911681526020016103e0565b34801561054057600080fd5b5061047561054f366004612965565b610d9a565b34801561056057600080fd5b5061047560075481565b34801561057657600080fd5b506103bc610585366004612a46565b610dde565b34801561059657600080fd5b5060155461040a90640100000000900462ffffff1681565b3480156105ba57600080fd5b5061047560145481565b3480156105d057600080fd5b506103bc6105df366004612965565b610de8565b3480156105f057600080fd5b50610475600e5481565b34801561060657600080fd5b50610475600d5481565b34801561061c57600080fd5b50601054610630906001600160a01b031681565b6040516001600160a01b0390911681526020016103e0565b34801561065457600080fd5b506103bc610663366004612a46565b610df9565b34801561067457600080fd5b50610475610683366004612965565b610e28565b34801561069457600080fd5b5061040a610bb881565b3480156106aa57600080fd5b5060155461040a90600160501b900462ffffff1681565b3480156106cd57600080fd5b50610475600a5481565b3480156106e357600080fd5b506104756106f2366004612965565b610e5e565b34801561070357600080fd5b506103bc610e9a565b34801561071857600080fd5b506103bc610727366004612a77565b610eae565b34801561073857600080fd5b506103bc6107473660046129d9565b610ef8565b6103bc610f11565b34801561076057600080fd5b506000546001600160a01b0316610630565b34801561077e57600080fd5b5061047561107b565b34801561079357600080fd5b506103bc6107a2366004612a46565b6110fb565b3480156107b357600080fd5b506103bc6111fc565b3480156107c857600080fd5b50610475611253565b3480156107dd57600080fd5b506103d36112c1565b3480156107f257600080fd5b506106307f000000000000000000000000000000000000000000000000000000000000000081565b34801561082657600080fd5b506104546108353660046129d9565b6112d0565b34801561084657600080fd5b506104756112de565b34801561085b57600080fd5b50610475611379565b34801561087057600080fd5b506103bc61087f366004612965565b61139a565b34801561089057600080fd5b506103bc61089f3660046129d9565b61142a565b3480156108b057600080fd5b5061063073e592427a0aece92de3edee1f18e0157c0586156481565b3480156108d857600080fd5b506103bc6108e7366004612a92565b6114e7565b3480156108f857600080fd5b506103bc611611565b34801561090d57600080fd5b506103bc61091c366004612a46565b611665565b34801561092d57600080fd5b506103bc61093c366004612a46565b6116a3565b34801561094d57600080fd5b506103bc61173f565b34801561096257600080fd5b50610475610971366004612ad5565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b3480156109a857600080fd5b506103bc611771565b3480156109bd57600080fd5b506104546109cc366004612965565b600c6020526000908152604090205460ff1681565b3480156109ed57600080fd5b506103bc6109fc366004612965565b6117a2565b348015610a0d57600080fd5b50610630736de037ef9ad2725eb40118bb1702ebb27e4aeb2481565b348015610a3557600080fd5b50610630737a250d5630b4cf539739df2c5dacb4c659f2488d81565b348015610a5d57600080fd5b5061047560135481565b348015610a7357600080fd5b506015546105229060ff1681565b348015610a8d57600080fd5b50610454610a9c366004612965565b6117dd565b306001600160a01b03821603610ae75760405162461bcd60e51b815260206004820152600660248201526502173776565760d41b60448201526064015b60405180910390fd5b736de037ef9ad2725eb40118bb1702ebb27e4aeb23196001600160a01b03821601610b3d5760405162461bcd60e51b815260206004820152600660248201526502173776565760d41b6044820152606401610ade565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba89190612b0e565b9050610bbe6001600160a01b03831633836117ea565b6040518181526001600160a01b0383169033907fed679328aebf74ede77ae09efcf36e90244f83643dadac1c2d9f0b21a46f6ab79060200160405180910390a35050565b606060048054610c1190612b27565b80601f0160208091040260200160405190810160405280929190818152602001828054610c3d90612b27565b8015610c8a5780601f10610c5f57610100808354040283529160200191610c8a565b820191906000526020600020905b815481529060010190602001808311610c6d57829003601f168201915b5050505050905090565b600033610ca281858561183c565b60019150505b92915050565b610cb6611849565b336000908152600860205260409020610cce81611873565b60018101546000819003610ce3575050610d67565b6000826001018190555080600a6000828254610cff9190612b77565b90915550610d249050736de037ef9ad2725eb40118bb1702ebb27e4aeb2484836117ea565b6040518181526001600160a01b0384169033907f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd9870689060200160405180910390a350505b610d716001600655565b50565b600033610d828582856118b4565b610d8d85858561192c565b60019150505b9392505050565b6001600160a01b03811660009081526008602090815260408083208151606081018352815481526001820154938101939093526002015490820152610ca89061198b565b610d713382611a07565b610df0611a3d565b610d7181611a6a565b6010546001600160a01b03163314610e235760405162461bcd60e51b8152600401610ade90612b8a565b600d55565b6000610e33826117dd565b15610e56576001600160a01b038216600090815260016020526040902054610ca8565b506000919050565b6000610e69826117dd565b1580610e335750610e78611abf565b610e56576001600160a01b038216600090815260016020526040902054610ca8565b610ea2611a3d565b610eac6000611ade565b565b6010546001600160a01b03163314610ed85760405162461bcd60e51b8152600401610ade90612b8a565b6015805462ffffff9092166101000263ffffff0019909216919091179055565b610f038233836118b4565b610f0d8282611a07565b5050565b610f19611a3d565b60003411610f565760405162461bcd60e51b815260206004820152600a602482015269216c697175696469747960b01b6044820152606401610ade565b60145415610f955760405162461bcd60e51b815260206004820152600c60248201526b085a5b9a5d1a585b1a5e995960a21b6044820152606401610ade565b436014556064610fa460035490565b610fae9190612bad565b6013556000610fbc30610e5e565b9050610fdd30737a250d5630b4cf539739df2c5dacb4c659f2488d8361183c565b60405163f305d71960e01b81523060048201526024810182905260006044820181905260648201523360848201524260a4820152737a250d5630b4cf539739df2c5dacb4c659f2488d9063f305d71990349060c40160606040518083038185885af1158015611050573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906110759190612bcf565b50505050565b6000600f5460000361108d5750600090565b600d5460000361109d5750600090565b60006110a76112de565b9050806000036110b957600091505090565b6000600f54436110c99190612bfd565b600d546110d69190612c10565b600e546110e39190612b77565b90508181106110f257816110f4565b805b9250505090565b6007546000036111085750565b600061111261107b565b905047801561113357611126308285611b2e565b6111309083612b77565b91505b8160000361114057505050565b600754670de0b6b3a76400006111767f000000000000000000000000000000000000000000000000000000000000000085612c10565b6111809190612c10565b61118a9190612bad565b6009600082825461119b9190612b77565b9250508190555081600b60008282546111b49190612b77565b90915550506000600e5543600f5560405182815233907fc1d32ad5cca423e7dda2123dbf8c482f8e77d00b631c06e903a47f2cec1334df9060200160405180910390a2505050565b61120533611d00565b336000818152600c6020908152604091829020805460ff1916905590519182527f9d987f025241c15852f6fdf907bfad8c5c84f316a13b8855ba5185bf79a3f7bb91015b60405180910390a1565b60008060006112626011611d68565b905060005b818110156112ac5761129861127d601183611d72565b6001600160a01b031660009081526001602052604090205490565b6112a29084612b77565b9250600101611267565b50816112b760035490565b6110f49190612bfd565b606060058054610c1190612b27565b600033610ca281858561192c565b600080600a54600b546112f19190612bfd565b6040516370a0823160e01b81523060048201529091508190736de037ef9ad2725eb40118bb1702ebb27e4aeb24906370a0823190602401602060405180830381865afa158015611345573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113699190612b0e565b6113739190612bfd565b91505090565b600061138361107b565b61138b6112de565b6113959190612bfd565b905090565b6010546001600160a01b031633146113c45760405162461bcd60e51b8152600401610ade90612b8a565b6001600160a01b0381166000036114085760405162461bcd60e51b8152602060048201526008602482015267216164647265737360c01b6044820152606401610ade565b601080546001600160a01b0319166001600160a01b0392909216919091179055565b611432611a3d565b601454156114715760405162461bcd60e51b815260206004820152600c60248201526b085a5b9a5d1a585b1a5e995960a21b6044820152606401610ade565b60405163a9059cbb60e01b81526001600160a01b038316600482015260248101829052309063a9059cbb906044016020604051808303816000875af11580156114be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e29190612c27565b505050565b6114ef611a3d565b610bb862ffffff841611156115305760405162461bcd60e51b81526020600482015260076024820152662162757946656560c81b6044820152606401610ade565b610bb862ffffff831611156115725760405162461bcd60e51b81526020600482015260086024820152672173656c6c46656560c01b6044820152606401610ade565b61271062ffffff821611156115b95760405162461bcd60e51b815260206004820152600d60248201526c216d61726b6574696e6746656560981b6044820152606401610ade565b6015805469ffffffffffff00000000191664010000000062ffffff9586160269ffffff00000000000000191617600160381b938516939093029290921762ffffff60501b1916600160501b9190931602919091179055565b61161a33611d7e565b336000818152600c6020908152604091829020805460ff1916600117905590519182527f6d2f2ea0335c8c0e296412085b47e0ed0c1b67b6bde3f5739e7739ca804a75b19101611249565b6010546001600160a01b0316331461168f5760405162461bcd60e51b8152600401610ade90612b8a565b61169761107b565b600e55600d5543600f55565b60006116ae30610e5e565b9050806000036116bc575050565b60006116c9308385611de7565b601554909150600090612710906116ec90600160501b900462ffffff1684612c10565b6116f69190612bad565b90508015611075576010546040516001600160a01b039091169082156108fc029083906000818181858888f19350505050158015611738573d6000803e3d6000fd5b5050505050565b6010546001600160a01b031633146117695760405162461bcd60e51b8152600401610ade90612b8a565b600019601355565b6010546001600160a01b0316331461179b5760405162461bcd60e51b8152600401610ade90612b8a565b6000600e55565b6117aa611a3d565b6001600160a01b0381166117d457604051631e4fbdf760e01b815260006004820152602401610ade565b610d7181611ade565b6000610ca8601183611f97565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526114e2908490611fb9565b6114e2838383600161201c565b60026006540361186c57604051633ee5aeb560e01b815260040160405180910390fd5b6002600655565b6040805160608101825282548152600183015460208201526002830154918101919091526000906118a39061198b565b600183015550600954600290910155565b6001600160a01b038381166000908152600260209081526040808320938616835292905220546000198114611075578181101561191d57604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610ade565b6110758484848403600061201c565b6001600160a01b03831661195657604051634b637e8f60e11b815260006004820152602401610ade565b6001600160a01b0382166119805760405163ec442f0560e01b815260006004820152602401610ade565b6114e28383836120f1565b60008082604001516009546119a09190612bfd565b905060006119d6670de0b6b3a76400007f0000000000000000000000000000000000000000000000000000000000000000612c10565b84516119e3908490612c10565b6119ed9190612bad565b90508084602001516119ff9190612b77565b949350505050565b6001600160a01b038216611a3157604051634b637e8f60e11b815260006004820152602401610ade565b610f0d826000836120f1565b6000546001600160a01b03163314610eac5760405163118cdaa760e01b8152336004820152602401610ade565b611a7381611d7e565b611a7e60118261230e565b506040516001600160a01b03821681527f3afada3900b4909463d8a846fbdc12d6b5c4e8030bd6bc1215822ecee62357ba906020015b60405180910390a150565b601554601454600091611ad79160ff90911690612b77565b4311905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600082600003611b4057506000610d93565b6000604051806101000160405280737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc49190612c49565b6001600160a01b039081168252736de037ef9ad2725eb40118bb1702ebb27e4aeb24602080840191909152601554610100900462ffffff9081166040808601919091528a84166060808701919091524260808088019190915260a08088018d905260c08089018d9052600060e0998a0152845163414bf38960e01b81528a5189166004820152968a015188166024880152938901519094166044860152908701518516606485015286015160848401529085015160a483015284015160c4820152918301511660e482015290915073e592427a0aece92de3edee1f18e0157c058615649063414bf3899086906101040160206040518083038185885af1158015611cd2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611cf79190612b0e565b95945050505050565b611d0981612323565b15611d115750565b6001600160a01b03811660009081526001602052604090205460076000828254611d3b9190612bfd565b90915550506001600160a01b0381166000908152600860205260409020611d6181611873565b6000905550565b6000610ca8825490565b6000610d9383836123a2565b611d8781612323565b611d8e5750565b6001600160a01b03811660009081526001602052604081205490508060076000828254611dbb9190612b77565b90915550506001600160a01b039091166000908152600860205260409020908155600954600290910155565b600082600003611df957506000610d93565b611e1830737a250d5630b4cf539739df2c5dacb4c659f2488d8561183c565b6040805160028082526060820183526000926020830190803683370190505090503081600081518110611e4d57611e4d612c66565b60200260200101906001600160a01b031690816001600160a01b031681525050737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ebf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee39190612c49565b81600181518110611ef657611ef6612c66565b6001600160a01b039092166020928302919091019091015260405163791ac94760e01b81524790737a250d5630b4cf539739df2c5dacb4c659f2488d9063791ac94790611f4f908890889087908c904290600401612c7c565b600060405180830381600087803b158015611f6957600080fd5b505af1158015611f7d573d6000803e3d6000fd5b505050508047611f8d9190612bfd565b9695505050505050565b6001600160a01b03811660009081526001830160205260408120541515610d93565b6000611fce6001600160a01b038416836123cc565b90508051600014158015611ff3575080806020019051810190611ff19190612c27565b155b156114e257604051635274afe760e01b81526001600160a01b0384166004820152602401610ade565b6001600160a01b0384166120465760405163e602df0560e01b815260006004820152602401610ade565b6001600160a01b03831661207057604051634a1406b160e11b815260006004820152602401610ade565b6001600160a01b038085166000908152600260209081526040808320938716835292905220829055801561107557826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516120e391815260200190565b60405180910390a350505050565b60006120fb611abf565b90506000846001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480156121465750612144846123da565b155b90506000612153866123da565b1580156121915750846001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316145b90508280156121a457506121a4866117dd565b156121da5760405162461bcd60e51b81526020600482015260066024820152651b1bd8dad95960d21b6044820152606401610ade565b6000816121e85760006121f8565b601554600160381b900462ffffff165b83612204576000612215565b601554640100000000900462ffffff165b61221f9190612cef565b62ffffff16905060006127106122358388612c10565b61223f9190612bad565b9050600061224d8288612bfd565b9050811561226057612260893084612411565b83156122705761227060006116a3565b61227b898983612411565b6122848961253b565b61228d8861253b565b851580156122a1575061229f8861259e565b155b156122af576122af8861260c565b6122b88861265a565b612303576013546122c889610e5e565b11156123035760405162461bcd60e51b815260206004820152600a602482015269085b585e15d85b1b195d60b21b6044820152606401610ade565b505050505050505050565b6000610d93836001600160a01b0384166126da565b60006001600160a01b03821615806123435750306001600160a01b038316145b8061237c57506000826001600160a01b03163b11801561237c57506001600160a01b0382166000908152600c602052604090205460ff16155b8061238b575061238b826117dd565b80610ca85750506001600160a01b031661dead1490565b60008260000182815481106123b9576123b9612c66565b9060005260206000200154905092915050565b6060610d93838360006127d4565b6000306001600160a01b0383161480610ca85750506001600160a01b0316737a250d5630b4cf539739df2c5dacb4c659f2488d1490565b6001600160a01b03831661243c5780600360008282546124319190612b77565b909155506124ae9050565b6001600160a01b0383166000908152600160205260409020548181101561248f5760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610ade565b6001600160a01b03841660009081526001602052604090209082900390555b6001600160a01b0382166124ca576003805482900390556124e9565b6001600160a01b03821660009081526001602052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161252e91815260200190565b60405180910390a3505050565b61254481612323565b1561254c5750565b600061255782610e5e565b6001600160a01b038316600090815260086020526040902080546007549293509091839161258491612bfd565b61258e9190612b77565b60075561259a81611873565b5550565b6000306001600160a01b03831614806125d35750737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b038316145b80610ca85750507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61261581611d00565b612620601182612867565b506040516001600160a01b03821681527f6b713f4f12b0a0860e4b6b54d27ef8de95da632b1250f5c12f8254fdedbc2ebd90602001611ab4565b6000306001600160a01b038316148061268f5750737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b038316145b806126cb5750816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316145b80610ca85750610ca8826117dd565b600081815260018301602052604081205480156127c35760006126fe600183612bfd565b855490915060009061271290600190612bfd565b905080821461277757600086600001828154811061273257612732612c66565b906000526020600020015490508087600001848154811061275557612755612c66565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061278857612788612d0b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610ca8565b6000915050610ca8565b5092915050565b6060814710156127f95760405163cd78605960e01b8152306004820152602401610ade565b600080856001600160a01b031684866040516128159190612d21565b60006040518083038185875af1925050503d8060008114612852576040519150601f19603f3d011682016040523d82523d6000602084013e612857565b606091505b5091509150611f8d86838361287c565b6000610d93836001600160a01b0384166128d8565b6060826128915761288c82612927565b610d93565b81511580156128a857506001600160a01b0384163b155b156128d157604051639996b31560e01b81526001600160a01b0385166004820152602401610ade565b5080610d93565b600081815260018301602052604081205461291f57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610ca8565b506000610ca8565b8051156129375780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114610d7157600080fd5b60006020828403121561297757600080fd5b8135610d9381612950565b60005b8381101561299d578181015183820152602001612985565b50506000910152565b60208152600082518060208401526129c5816040850160208701612982565b601f01601f19169190910160400192915050565b600080604083850312156129ec57600080fd5b82356129f781612950565b946020939093013593505050565b600080600060608486031215612a1a57600080fd5b8335612a2581612950565b92506020840135612a3581612950565b929592945050506040919091013590565b600060208284031215612a5857600080fd5b5035919050565b803562ffffff81168114612a7257600080fd5b919050565b600060208284031215612a8957600080fd5b610d9382612a5f565b600080600060608486031215612aa757600080fd5b612ab084612a5f565b9250612abe60208501612a5f565b9150612acc60408501612a5f565b90509250925092565b60008060408385031215612ae857600080fd5b8235612af381612950565b91506020830135612b0381612950565b809150509250929050565b600060208284031215612b2057600080fd5b5051919050565b600181811c90821680612b3b57607f821691505b602082108103612b5b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610ca857610ca8612b61565b60208082526009908201526810b7b832b930ba37b960b91b604082015260600190565b600082612bca57634e487b7160e01b600052601260045260246000fd5b500490565b600080600060608486031215612be457600080fd5b8351925060208401519150604084015190509250925092565b81810381811115610ca857610ca8612b61565b8082028115828204841417610ca857610ca8612b61565b600060208284031215612c3957600080fd5b81518015158114610d9357600080fd5b600060208284031215612c5b57600080fd5b8151610d9381612950565b634e487b7160e01b600052603260045260246000fd5b600060a08201878352602087602085015260a0604085015281875180845260c08601915060208901935060005b81811015612cce5784516001600160a01b031683529383019391830191600101612ca9565b50506001600160a01b03969096166060850152505050608001529392505050565b62ffffff8181168382160190808211156127cd576127cd612b61565b634e487b7160e01b600052603160045260246000fd5b60008251612d33818460208701612982565b919091019291505056fea26469706673582212207a7a5a501753de715e3980387dd811393caf84f2158a1d2aea9f477f2bb162a464736f6c634300081700330000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d

Deployed Bytecode

0x6080604052600436106103905760003560e01c806373dd250c116101dc578063c31c9c0711610102578063e7e3a24d116100a0578063f887ea401161006f578063f887ea4014610a29578063f8b45b0514610a51578063fabb0b4f14610a67578063fe575a8714610a8157600080fd5b8063e7e3a24d1461099c578063e7e82b69146109b1578063f2fde38b146109e1578063f7c618c114610a0157600080fd5b8063d7406965116100dc578063d740696514610901578063dbfa0bb514610921578063dc07b61714610941578063dd62ed3e1461095657600080fd5b8063c31c9c07146108a4578063c38ed941146108cc578063cebd7ae8146108ec57600080fd5b80639358928b1161017a578063aa5c3ab411610149578063aa5c3ab41461083a578063afb62e561461084f578063b3ab15fb14610864578063b78b52df1461088457600080fd5b80639358928b146107bc57806395d89b41146107d1578063a8aa1b31146107e6578063a9059cbb1461081a57600080fd5b80638da5cb5b116101b65780638da5cb5b14610754578063909921c71461077257806391c05b0b146107875780639266cc2a146107a757600080fd5b806373dd250c1461070c57806379cc67901461072c5780638129fc1c1461074c57600080fd5b80633a98ef39116102c1578063570ca7351161025f5780636b67c4df1161022e5780636b67c4df1461069e5780636f83f6a2146106c157806370a08231146106d7578063715018a6146106f757600080fd5b8063570ca7351461061057806359303a1114610648578063593557361461066857806366edecce1461068857600080fd5b806348cd4cb11161029b57806348cd4cb1146105ae578063537df3b6146105c45780635428c9cb146105e4578063554c798a146105fa57600080fd5b80633a98ef391461055457806342966c681461056a578063470624021461058a57600080fd5b80631e83409a1161032e5780632b14ca56116103085780632b14ca56146104d957806330188ee8146104fc578063313ce5671461051257806331d7a2621461053457600080fd5b80631e83409a146104835780632251c730146104a357806323b872dd146104b957600080fd5b806309094d661161036a57806309094d661461041e578063095ea7b314610434578063180b0d7e1461041e57806318160ddd1461046457600080fd5b806301681a621461039c57806306fdde03146103be578063089fe6aa146103e957600080fd5b3661039757005b600080fd5b3480156103a857600080fd5b506103bc6103b7366004612965565b610aa1565b005b3480156103ca57600080fd5b506103d3610c02565b6040516103e091906129a6565b60405180910390f35b3480156103f557600080fd5b5060155461040a90610100900462ffffff1681565b60405162ffffff90911681526020016103e0565b34801561042a57600080fd5b5061040a61271081565b34801561044057600080fd5b5061045461044f3660046129d9565b610c94565b60405190151581526020016103e0565b34801561047057600080fd5b506003545b6040519081526020016103e0565b34801561048f57600080fd5b506103bc61049e366004612965565b610cae565b3480156104af57600080fd5b50610475600f5481565b3480156104c557600080fd5b506104546104d4366004612a05565b610d74565b3480156104e557600080fd5b5060155461040a90600160381b900462ffffff1681565b34801561050857600080fd5b50610475600b5481565b34801561051e57600080fd5b5060125b60405160ff90911681526020016103e0565b34801561054057600080fd5b5061047561054f366004612965565b610d9a565b34801561056057600080fd5b5061047560075481565b34801561057657600080fd5b506103bc610585366004612a46565b610dde565b34801561059657600080fd5b5060155461040a90640100000000900462ffffff1681565b3480156105ba57600080fd5b5061047560145481565b3480156105d057600080fd5b506103bc6105df366004612965565b610de8565b3480156105f057600080fd5b50610475600e5481565b34801561060657600080fd5b50610475600d5481565b34801561061c57600080fd5b50601054610630906001600160a01b031681565b6040516001600160a01b0390911681526020016103e0565b34801561065457600080fd5b506103bc610663366004612a46565b610df9565b34801561067457600080fd5b50610475610683366004612965565b610e28565b34801561069457600080fd5b5061040a610bb881565b3480156106aa57600080fd5b5060155461040a90600160501b900462ffffff1681565b3480156106cd57600080fd5b50610475600a5481565b3480156106e357600080fd5b506104756106f2366004612965565b610e5e565b34801561070357600080fd5b506103bc610e9a565b34801561071857600080fd5b506103bc610727366004612a77565b610eae565b34801561073857600080fd5b506103bc6107473660046129d9565b610ef8565b6103bc610f11565b34801561076057600080fd5b506000546001600160a01b0316610630565b34801561077e57600080fd5b5061047561107b565b34801561079357600080fd5b506103bc6107a2366004612a46565b6110fb565b3480156107b357600080fd5b506103bc6111fc565b3480156107c857600080fd5b50610475611253565b3480156107dd57600080fd5b506103d36112c1565b3480156107f257600080fd5b506106307f0000000000000000000000009a633671df5f36506fc513064eda0cdf83cb0c1381565b34801561082657600080fd5b506104546108353660046129d9565b6112d0565b34801561084657600080fd5b506104756112de565b34801561085b57600080fd5b50610475611379565b34801561087057600080fd5b506103bc61087f366004612965565b61139a565b34801561089057600080fd5b506103bc61089f3660046129d9565b61142a565b3480156108b057600080fd5b5061063073e592427a0aece92de3edee1f18e0157c0586156481565b3480156108d857600080fd5b506103bc6108e7366004612a92565b6114e7565b3480156108f857600080fd5b506103bc611611565b34801561090d57600080fd5b506103bc61091c366004612a46565b611665565b34801561092d57600080fd5b506103bc61093c366004612a46565b6116a3565b34801561094d57600080fd5b506103bc61173f565b34801561096257600080fd5b50610475610971366004612ad5565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b3480156109a857600080fd5b506103bc611771565b3480156109bd57600080fd5b506104546109cc366004612965565b600c6020526000908152604090205460ff1681565b3480156109ed57600080fd5b506103bc6109fc366004612965565b6117a2565b348015610a0d57600080fd5b50610630736de037ef9ad2725eb40118bb1702ebb27e4aeb2481565b348015610a3557600080fd5b50610630737a250d5630b4cf539739df2c5dacb4c659f2488d81565b348015610a5d57600080fd5b5061047560135481565b348015610a7357600080fd5b506015546105229060ff1681565b348015610a8d57600080fd5b50610454610a9c366004612965565b6117dd565b306001600160a01b03821603610ae75760405162461bcd60e51b815260206004820152600660248201526502173776565760d41b60448201526064015b60405180910390fd5b736de037ef9ad2725eb40118bb1702ebb27e4aeb23196001600160a01b03821601610b3d5760405162461bcd60e51b815260206004820152600660248201526502173776565760d41b6044820152606401610ade565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba89190612b0e565b9050610bbe6001600160a01b03831633836117ea565b6040518181526001600160a01b0383169033907fed679328aebf74ede77ae09efcf36e90244f83643dadac1c2d9f0b21a46f6ab79060200160405180910390a35050565b606060048054610c1190612b27565b80601f0160208091040260200160405190810160405280929190818152602001828054610c3d90612b27565b8015610c8a5780601f10610c5f57610100808354040283529160200191610c8a565b820191906000526020600020905b815481529060010190602001808311610c6d57829003601f168201915b5050505050905090565b600033610ca281858561183c565b60019150505b92915050565b610cb6611849565b336000908152600860205260409020610cce81611873565b60018101546000819003610ce3575050610d67565b6000826001018190555080600a6000828254610cff9190612b77565b90915550610d249050736de037ef9ad2725eb40118bb1702ebb27e4aeb2484836117ea565b6040518181526001600160a01b0384169033907f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd9870689060200160405180910390a350505b610d716001600655565b50565b600033610d828582856118b4565b610d8d85858561192c565b60019150505b9392505050565b6001600160a01b03811660009081526008602090815260408083208151606081018352815481526001820154938101939093526002015490820152610ca89061198b565b610d713382611a07565b610df0611a3d565b610d7181611a6a565b6010546001600160a01b03163314610e235760405162461bcd60e51b8152600401610ade90612b8a565b600d55565b6000610e33826117dd565b15610e56576001600160a01b038216600090815260016020526040902054610ca8565b506000919050565b6000610e69826117dd565b1580610e335750610e78611abf565b610e56576001600160a01b038216600090815260016020526040902054610ca8565b610ea2611a3d565b610eac6000611ade565b565b6010546001600160a01b03163314610ed85760405162461bcd60e51b8152600401610ade90612b8a565b6015805462ffffff9092166101000263ffffff0019909216919091179055565b610f038233836118b4565b610f0d8282611a07565b5050565b610f19611a3d565b60003411610f565760405162461bcd60e51b815260206004820152600a602482015269216c697175696469747960b01b6044820152606401610ade565b60145415610f955760405162461bcd60e51b815260206004820152600c60248201526b085a5b9a5d1a585b1a5e995960a21b6044820152606401610ade565b436014556064610fa460035490565b610fae9190612bad565b6013556000610fbc30610e5e565b9050610fdd30737a250d5630b4cf539739df2c5dacb4c659f2488d8361183c565b60405163f305d71960e01b81523060048201526024810182905260006044820181905260648201523360848201524260a4820152737a250d5630b4cf539739df2c5dacb4c659f2488d9063f305d71990349060c40160606040518083038185885af1158015611050573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906110759190612bcf565b50505050565b6000600f5460000361108d5750600090565b600d5460000361109d5750600090565b60006110a76112de565b9050806000036110b957600091505090565b6000600f54436110c99190612bfd565b600d546110d69190612c10565b600e546110e39190612b77565b90508181106110f257816110f4565b805b9250505090565b6007546000036111085750565b600061111261107b565b905047801561113357611126308285611b2e565b6111309083612b77565b91505b8160000361114057505050565b600754670de0b6b3a76400006111767f000000000000000000000000000000000000000000000000000000000000000185612c10565b6111809190612c10565b61118a9190612bad565b6009600082825461119b9190612b77565b9250508190555081600b60008282546111b49190612b77565b90915550506000600e5543600f5560405182815233907fc1d32ad5cca423e7dda2123dbf8c482f8e77d00b631c06e903a47f2cec1334df9060200160405180910390a2505050565b61120533611d00565b336000818152600c6020908152604091829020805460ff1916905590519182527f9d987f025241c15852f6fdf907bfad8c5c84f316a13b8855ba5185bf79a3f7bb91015b60405180910390a1565b60008060006112626011611d68565b905060005b818110156112ac5761129861127d601183611d72565b6001600160a01b031660009081526001602052604090205490565b6112a29084612b77565b9250600101611267565b50816112b760035490565b6110f49190612bfd565b606060058054610c1190612b27565b600033610ca281858561192c565b600080600a54600b546112f19190612bfd565b6040516370a0823160e01b81523060048201529091508190736de037ef9ad2725eb40118bb1702ebb27e4aeb24906370a0823190602401602060405180830381865afa158015611345573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113699190612b0e565b6113739190612bfd565b91505090565b600061138361107b565b61138b6112de565b6113959190612bfd565b905090565b6010546001600160a01b031633146113c45760405162461bcd60e51b8152600401610ade90612b8a565b6001600160a01b0381166000036114085760405162461bcd60e51b8152602060048201526008602482015267216164647265737360c01b6044820152606401610ade565b601080546001600160a01b0319166001600160a01b0392909216919091179055565b611432611a3d565b601454156114715760405162461bcd60e51b815260206004820152600c60248201526b085a5b9a5d1a585b1a5e995960a21b6044820152606401610ade565b60405163a9059cbb60e01b81526001600160a01b038316600482015260248101829052309063a9059cbb906044016020604051808303816000875af11580156114be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e29190612c27565b505050565b6114ef611a3d565b610bb862ffffff841611156115305760405162461bcd60e51b81526020600482015260076024820152662162757946656560c81b6044820152606401610ade565b610bb862ffffff831611156115725760405162461bcd60e51b81526020600482015260086024820152672173656c6c46656560c01b6044820152606401610ade565b61271062ffffff821611156115b95760405162461bcd60e51b815260206004820152600d60248201526c216d61726b6574696e6746656560981b6044820152606401610ade565b6015805469ffffffffffff00000000191664010000000062ffffff9586160269ffffff00000000000000191617600160381b938516939093029290921762ffffff60501b1916600160501b9190931602919091179055565b61161a33611d7e565b336000818152600c6020908152604091829020805460ff1916600117905590519182527f6d2f2ea0335c8c0e296412085b47e0ed0c1b67b6bde3f5739e7739ca804a75b19101611249565b6010546001600160a01b0316331461168f5760405162461bcd60e51b8152600401610ade90612b8a565b61169761107b565b600e55600d5543600f55565b60006116ae30610e5e565b9050806000036116bc575050565b60006116c9308385611de7565b601554909150600090612710906116ec90600160501b900462ffffff1684612c10565b6116f69190612bad565b90508015611075576010546040516001600160a01b039091169082156108fc029083906000818181858888f19350505050158015611738573d6000803e3d6000fd5b5050505050565b6010546001600160a01b031633146117695760405162461bcd60e51b8152600401610ade90612b8a565b600019601355565b6010546001600160a01b0316331461179b5760405162461bcd60e51b8152600401610ade90612b8a565b6000600e55565b6117aa611a3d565b6001600160a01b0381166117d457604051631e4fbdf760e01b815260006004820152602401610ade565b610d7181611ade565b6000610ca8601183611f97565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526114e2908490611fb9565b6114e2838383600161201c565b60026006540361186c57604051633ee5aeb560e01b815260040160405180910390fd5b6002600655565b6040805160608101825282548152600183015460208201526002830154918101919091526000906118a39061198b565b600183015550600954600290910155565b6001600160a01b038381166000908152600260209081526040808320938616835292905220546000198114611075578181101561191d57604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610ade565b6110758484848403600061201c565b6001600160a01b03831661195657604051634b637e8f60e11b815260006004820152602401610ade565b6001600160a01b0382166119805760405163ec442f0560e01b815260006004820152602401610ade565b6114e28383836120f1565b60008082604001516009546119a09190612bfd565b905060006119d6670de0b6b3a76400007f0000000000000000000000000000000000000000000000000000000000000001612c10565b84516119e3908490612c10565b6119ed9190612bad565b90508084602001516119ff9190612b77565b949350505050565b6001600160a01b038216611a3157604051634b637e8f60e11b815260006004820152602401610ade565b610f0d826000836120f1565b6000546001600160a01b03163314610eac5760405163118cdaa760e01b8152336004820152602401610ade565b611a7381611d7e565b611a7e60118261230e565b506040516001600160a01b03821681527f3afada3900b4909463d8a846fbdc12d6b5c4e8030bd6bc1215822ecee62357ba906020015b60405180910390a150565b601554601454600091611ad79160ff90911690612b77565b4311905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600082600003611b4057506000610d93565b6000604051806101000160405280737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc49190612c49565b6001600160a01b039081168252736de037ef9ad2725eb40118bb1702ebb27e4aeb24602080840191909152601554610100900462ffffff9081166040808601919091528a84166060808701919091524260808088019190915260a08088018d905260c08089018d9052600060e0998a0152845163414bf38960e01b81528a5189166004820152968a015188166024880152938901519094166044860152908701518516606485015286015160848401529085015160a483015284015160c4820152918301511660e482015290915073e592427a0aece92de3edee1f18e0157c058615649063414bf3899086906101040160206040518083038185885af1158015611cd2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611cf79190612b0e565b95945050505050565b611d0981612323565b15611d115750565b6001600160a01b03811660009081526001602052604090205460076000828254611d3b9190612bfd565b90915550506001600160a01b0381166000908152600860205260409020611d6181611873565b6000905550565b6000610ca8825490565b6000610d9383836123a2565b611d8781612323565b611d8e5750565b6001600160a01b03811660009081526001602052604081205490508060076000828254611dbb9190612b77565b90915550506001600160a01b039091166000908152600860205260409020908155600954600290910155565b600082600003611df957506000610d93565b611e1830737a250d5630b4cf539739df2c5dacb4c659f2488d8561183c565b6040805160028082526060820183526000926020830190803683370190505090503081600081518110611e4d57611e4d612c66565b60200260200101906001600160a01b031690816001600160a01b031681525050737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ebf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee39190612c49565b81600181518110611ef657611ef6612c66565b6001600160a01b039092166020928302919091019091015260405163791ac94760e01b81524790737a250d5630b4cf539739df2c5dacb4c659f2488d9063791ac94790611f4f908890889087908c904290600401612c7c565b600060405180830381600087803b158015611f6957600080fd5b505af1158015611f7d573d6000803e3d6000fd5b505050508047611f8d9190612bfd565b9695505050505050565b6001600160a01b03811660009081526001830160205260408120541515610d93565b6000611fce6001600160a01b038416836123cc565b90508051600014158015611ff3575080806020019051810190611ff19190612c27565b155b156114e257604051635274afe760e01b81526001600160a01b0384166004820152602401610ade565b6001600160a01b0384166120465760405163e602df0560e01b815260006004820152602401610ade565b6001600160a01b03831661207057604051634a1406b160e11b815260006004820152602401610ade565b6001600160a01b038085166000908152600260209081526040808320938716835292905220829055801561107557826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516120e391815260200190565b60405180910390a350505050565b60006120fb611abf565b90506000846001600160a01b03167f0000000000000000000000009a633671df5f36506fc513064eda0cdf83cb0c136001600160a01b03161480156121465750612144846123da565b155b90506000612153866123da565b1580156121915750846001600160a01b03167f0000000000000000000000009a633671df5f36506fc513064eda0cdf83cb0c136001600160a01b0316145b90508280156121a457506121a4866117dd565b156121da5760405162461bcd60e51b81526020600482015260066024820152651b1bd8dad95960d21b6044820152606401610ade565b6000816121e85760006121f8565b601554600160381b900462ffffff165b83612204576000612215565b601554640100000000900462ffffff165b61221f9190612cef565b62ffffff16905060006127106122358388612c10565b61223f9190612bad565b9050600061224d8288612bfd565b9050811561226057612260893084612411565b83156122705761227060006116a3565b61227b898983612411565b6122848961253b565b61228d8861253b565b851580156122a1575061229f8861259e565b155b156122af576122af8861260c565b6122b88861265a565b612303576013546122c889610e5e565b11156123035760405162461bcd60e51b815260206004820152600a602482015269085b585e15d85b1b195d60b21b6044820152606401610ade565b505050505050505050565b6000610d93836001600160a01b0384166126da565b60006001600160a01b03821615806123435750306001600160a01b038316145b8061237c57506000826001600160a01b03163b11801561237c57506001600160a01b0382166000908152600c602052604090205460ff16155b8061238b575061238b826117dd565b80610ca85750506001600160a01b031661dead1490565b60008260000182815481106123b9576123b9612c66565b9060005260206000200154905092915050565b6060610d93838360006127d4565b6000306001600160a01b0383161480610ca85750506001600160a01b0316737a250d5630b4cf539739df2c5dacb4c659f2488d1490565b6001600160a01b03831661243c5780600360008282546124319190612b77565b909155506124ae9050565b6001600160a01b0383166000908152600160205260409020548181101561248f5760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610ade565b6001600160a01b03841660009081526001602052604090209082900390555b6001600160a01b0382166124ca576003805482900390556124e9565b6001600160a01b03821660009081526001602052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161252e91815260200190565b60405180910390a3505050565b61254481612323565b1561254c5750565b600061255782610e5e565b6001600160a01b038316600090815260086020526040902080546007549293509091839161258491612bfd565b61258e9190612b77565b60075561259a81611873565b5550565b6000306001600160a01b03831614806125d35750737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b038316145b80610ca85750507f0000000000000000000000009a633671df5f36506fc513064eda0cdf83cb0c136001600160a01b0390811691161490565b61261581611d00565b612620601182612867565b506040516001600160a01b03821681527f6b713f4f12b0a0860e4b6b54d27ef8de95da632b1250f5c12f8254fdedbc2ebd90602001611ab4565b6000306001600160a01b038316148061268f5750737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b038316145b806126cb5750816001600160a01b03167f0000000000000000000000009a633671df5f36506fc513064eda0cdf83cb0c136001600160a01b0316145b80610ca85750610ca8826117dd565b600081815260018301602052604081205480156127c35760006126fe600183612bfd565b855490915060009061271290600190612bfd565b905080821461277757600086600001828154811061273257612732612c66565b906000526020600020015490508087600001848154811061275557612755612c66565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061278857612788612d0b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610ca8565b6000915050610ca8565b5092915050565b6060814710156127f95760405163cd78605960e01b8152306004820152602401610ade565b600080856001600160a01b031684866040516128159190612d21565b60006040518083038185875af1925050503d8060008114612852576040519150601f19603f3d011682016040523d82523d6000602084013e612857565b606091505b5091509150611f8d86838361287c565b6000610d93836001600160a01b0384166128d8565b6060826128915761288c82612927565b610d93565b81511580156128a857506001600160a01b0384163b155b156128d157604051639996b31560e01b81526001600160a01b0385166004820152602401610ade565b5080610d93565b600081815260018301602052604081205461291f57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610ca8565b506000610ca8565b8051156129375780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114610d7157600080fd5b60006020828403121561297757600080fd5b8135610d9381612950565b60005b8381101561299d578181015183820152602001612985565b50506000910152565b60208152600082518060208401526129c5816040850160208701612982565b601f01601f19169190910160400192915050565b600080604083850312156129ec57600080fd5b82356129f781612950565b946020939093013593505050565b600080600060608486031215612a1a57600080fd5b8335612a2581612950565b92506020840135612a3581612950565b929592945050506040919091013590565b600060208284031215612a5857600080fd5b5035919050565b803562ffffff81168114612a7257600080fd5b919050565b600060208284031215612a8957600080fd5b610d9382612a5f565b600080600060608486031215612aa757600080fd5b612ab084612a5f565b9250612abe60208501612a5f565b9150612acc60408501612a5f565b90509250925092565b60008060408385031215612ae857600080fd5b8235612af381612950565b91506020830135612b0381612950565b809150509250929050565b600060208284031215612b2057600080fd5b5051919050565b600181811c90821680612b3b57607f821691505b602082108103612b5b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610ca857610ca8612b61565b60208082526009908201526810b7b832b930ba37b960b91b604082015260600190565b600082612bca57634e487b7160e01b600052601260045260246000fd5b500490565b600080600060608486031215612be457600080fd5b8351925060208401519150604084015190509250925092565b81810381811115610ca857610ca8612b61565b8082028115828204841417610ca857610ca8612b61565b600060208284031215612c3957600080fd5b81518015158114610d9357600080fd5b600060208284031215612c5b57600080fd5b8151610d9381612950565b634e487b7160e01b600052603260045260246000fd5b600060a08201878352602087602085015260a0604085015281875180845260c08601915060208901935060005b81811015612cce5784516001600160a01b031683529383019391830191600101612ca9565b50506001600160a01b03969096166060850152505050608001529392505050565b62ffffff8181168382160190808211156127cd576127cd612b61565b634e487b7160e01b600052603160045260246000fd5b60008251612d33818460208701612982565b919091019291505056fea26469706673582212207a7a5a501753de715e3980387dd811393caf84f2158a1d2aea9f477f2bb162a464736f6c63430008170033

Deployed Bytecode Sourcemap

97130:95:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83706:375;;;;;;;;;;-1:-1:-1;83706:375:0;;;;;:::i;:::-;;:::i;:::-;;15879:91;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;74930:29;;;;;;;;;;-1:-1:-1;74930:29:0;;;;;;;;;;;;;;1262:8:1;1250:21;;;1232:40;;1220:2;1205:18;74930:29:0;1088:190:1;75213:46:0;;;;;;;;;;;;75254:5;75213:46;;18172:190;;;;;;;;;;-1:-1:-1;18172:190:0;;;;;:::i;:::-;;:::i;:::-;;;1776:14:1;;1769:22;1751:41;;1739:2;1724:18;18172:190:0;1611:187:1;16981:99:0;;;;;;;;;;-1:-1:-1;17060:12:0;;16981:99;;;1949:25:1;;;1937:2;1922:18;16981:99:0;1803:177:1;80933:418:0;;;;;;;;;;-1:-1:-1;80933:418:0;;;;;:::i;:::-;;:::i;73661:32::-;;;;;;;;;;;;;;;;18940:249;;;;;;;;;;-1:-1:-1;18940:249:0;;;;;:::i;:::-;;:::i;75354:28::-;;;;;;;;;;-1:-1:-1;75354:28:0;;;;-1:-1:-1;;;75354:28:0;;;;;;73054:37;;;;;;;;;;;;;;;;16832:84;;;;;;;;;;-1:-1:-1;16906:2:0;16832:84;;;2894:4:1;2882:17;;;2864:36;;2852:2;2837:18;16832:84:0;2722:184:1;80518:131:0;;;;;;;;;;-1:-1:-1;80518:131:0;;;;;:::i;:::-;;:::i;72600:26::-;;;;;;;;;;;;;;;;41720:89;;;;;;;;;;-1:-1:-1;41720:89:0;;;;;:::i;:::-;;:::i;75320:27::-;;;;;;;;;;-1:-1:-1;75320:27:0;;;;;;;;;;;74670:29;;;;;;;;;;;;;;;;85031:107;;;;;;;;;;-1:-1:-1;85031:107:0;;;;;:::i;:::-;;:::i;73567:34::-;;;;;;;;;;;;;;;;73449;;;;;;;;;;;;;;;;74309:23;;;;;;;;;;-1:-1:-1;74309:23:0;;;;-1:-1:-1;;;;;74309:23:0;;;;;;-1:-1:-1;;;;;3260:32:1;;;3242:51;;3230:2;3215:18;74309:23:0;3096:203:1;87387:151:0;;;;;;;;;;-1:-1:-1;87387:151:0;;;;;:::i;:::-;;:::i;78880:197::-;;;;;;;;;;-1:-1:-1;78880:197:0;;;;;:::i;:::-;;:::i;75166:40::-;;;;;;;;;;;;75202:4;75166:40;;75389:34;;;;;;;;;;-1:-1:-1;75389:34:0;;;;-1:-1:-1;;;75389:34:0;;;;;;72956:33;;;;;;;;;;;;;;;;78525:225;;;;;;;;;;-1:-1:-1;78525:225:0;;;;;:::i;:::-;;:::i;3151:103::-;;;;;;;;;;;;;:::i;86757:96::-;;;;;;;;;;-1:-1:-1;86757:96:0;;;;;:::i;:::-;;:::i;42138:161::-;;;;;;;;;;-1:-1:-1;42138:161:0;;;;;:::i;:::-;;:::i;85416:690::-;;;:::i;2476:87::-;;;;;;;;;;-1:-1:-1;2522:7:0;2549:6;-1:-1:-1;;;;;2549:6:0;2476:87;;80014:413;;;;;;;;;;;;;:::i;82679:937::-;;;;;;;;;;-1:-1:-1;82679:937:0;;;;;:::i;:::-;;:::i;81704:158::-;;;;;;;;;;;;;:::i;78071:316::-;;;;;;;;;;;;;:::i;16089:95::-;;;;;;;;;;;;;:::i;71755:36::-;;;;;;;;;;;;;;;17466:182;;;;;;;;;;-1:-1:-1;17466:182:0;;;;;:::i;:::-;;:::i;79458:213::-;;;;;;;;;;;;;:::i;79142:118::-;;;;;;;;;;;;;:::i;86370:156::-;;;;;;;;;;-1:-1:-1;86370:156:0;;;;;:::i;:::-;;:::i;84372:162::-;;;;;;;;;;-1:-1:-1;84372:162:0;;;;;:::i;:::-;;:::i;71286:96::-;;;;;;;;;;;;71339:42;71286:96;;84582:370;;;;;;;;;;-1:-1:-1;84582:370:0;;;;;:::i;:::-;;:::i;81451:154::-;;;;;;;;;;;;;:::i;87003:237::-;;;;;;;;;;-1:-1:-1;87003:237:0;;;;;:::i;:::-;;:::i;82002:543::-;;;;;;;;;;-1:-1:-1;82002:543:0;;;;;:::i;:::-;;:::i;86597:97::-;;;;;;;;;;;;;:::i;17711:142::-;;;;;;;;;;-1:-1:-1;17711:142:0;;;;;:::i;:::-;-1:-1:-1;;;;;17818:18:0;;;17791:7;17818:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;17711:142;87626:101;;;;;;;;;;;;;:::i;73154:39::-;;;;;;;;;;-1:-1:-1;73154:39:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;3409:220;;;;;;;;;;-1:-1:-1;3409:220:0;;;;;:::i;:::-;;:::i;71502:103::-;;;;;;;;;;;;71562:42;71502:103;;71389:106;;;;;;;;;;;;71452:42;71389:106;;74592:44;;;;;;;;;;;;;;;;74706:27;;;;;;;;;;-1:-1:-1;74706:27:0;;;;;;;;77725:114;;;;;;;;;;-1:-1:-1;77725:114:0;;;;;:::i;:::-;;:::i;83706:375::-;83799:4;-1:-1:-1;;;;;83768:36:0;;;83760:55;;;;-1:-1:-1;;;83760:55:0;;5527:2:1;83760:55:0;;;5509:21:1;5566:1;5546:18;;;5539:29;-1:-1:-1;;;5584:18:1;;;5577:36;5630:18;;83760:55:0;;;;;;;;;-1:-1:-1;;;;;;;83834:43:0;;;83826:62;;;;-1:-1:-1;;;83826:62:0;;5527:2:1;83826:62:0;;;5509:21:1;5566:1;5546:18;;;5539:29;-1:-1:-1;;;5584:18:1;;;5577:36;5630:18;;83826:62:0;5325:329:1;83826:62:0;83918:35;;-1:-1:-1;;;83918:35:0;;83947:4;83918:35;;;3242:51:1;83901:14:0;;-1:-1:-1;;;;;83918:20:0;;;;;3215:18:1;;83918:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;83901:52;-1:-1:-1;83966:43:0;-1:-1:-1;;;;;83966:23:0;;83990:10;83901:52;83966:23;:43::i;:::-;84027:46;;1949:25:1;;;-1:-1:-1;;;;;84027:46:0;;;84033:10;;84027:46;;1937:2:1;1922:18;84027:46:0;;;;;;;83749:332;83706:375;:::o;15879:91::-;15924:13;15957:5;15950:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15879:91;:::o;18172:190::-;18245:4;831:10;18301:31;831:10;18317:7;18326:5;18301:8;:31::i;:::-;18350:4;18343:11;;;18172:190;;;;;:::o;80933:418::-;44656:21;:19;:21::i;:::-;81028:10:::1;80993:19;81015:24:::0;;;:12:::1;:24;::::0;;;;81052:12:::1;81015:24:::0;81052:5:::1;:12::i;:::-;81101;::::0;::::1;::::0;81077:21:::1;81130:18:::0;;;81126:31:::1;;81150:7;;;;81126:31;81184:1;81169:5;:12;;:16;;;;81220:13;81198:18;;:35;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;81246:43:0::1;::::0;-1:-1:-1;71562:42:0::1;81271:2:::0;81275:13;81246:24:::1;:43::i;:::-;81307:36;::::0;1949:25:1;;;-1:-1:-1;;;;;81307:36:0;::::1;::::0;81313:10:::1;::::0;81307:36:::1;::::0;1937:2:1;1922:18;81307:36:0::1;;;;;;;80982:369;;44688:1;44700:20:::0;43991:1;45242:7;:21;45059:212;44700:20;80933:418;:::o;18940:249::-;19027:4;831:10;19085:37;19101:4;831:10;19116:5;19085:15;:37::i;:::-;19133:26;19143:4;19149:2;19153:5;19133:9;:26::i;:::-;19177:4;19170:11;;;18940:249;;;;;;:::o;80518:131::-;-1:-1:-1;;;;;80622:18:0;;80579:7;80622:18;;;:12;:18;;;;;;;;80606:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:15;:35::i;41720:89::-;41775:26;831:10;41795:5;41775;:26::i;85031:107::-;2362:13;:11;:13::i;:::-;85104:26:::1;85125:4;85104:20;:26::i;87387:151::-:0;76226:8;;-1:-1:-1;;;;;76226:8:0;76212:10;:22;76204:44;;;;-1:-1:-1;;;76204:44:0;;;;;;;:::i;:::-;87488:19:::1;:42:::0;87387:151::o;78880:197::-;78943:7;78967:22;78981:7;78967:13;:22::i;:::-;78963:86;;;-1:-1:-1;;;;;17235:18:0;;17208:7;17235:18;;;:9;:18;;;;;;79013:24;17143:118;78963:86;-1:-1:-1;79068:1:0;;78880:197;-1:-1:-1;78880:197:0:o;78525:225::-;78591:7;78616:22;78630:7;78616:13;:22::i;:::-;78615:23;:47;;;;78643:19;:17;:19::i;:::-;78611:111;;-1:-1:-1;;;;;17235:18:0;;17208:7;17235:18;;;:9;:18;;;;;;78686:24;17143:118;3151:103;2362:13;:11;:13::i;:::-;3216:30:::1;3243:1;3216:18;:30::i;:::-;3151:103::o:0;86757:96::-;76226:8;;-1:-1:-1;;;;;76226:8:0;76212:10;:22;76204:44;;;;-1:-1:-1;;;76204:44:0;;;;;;;:::i;:::-;86827:7:::1;:18:::0;;::::1;::::0;;::::1;;;-1:-1:-1::0;;86827:18:0;;::::1;::::0;;;::::1;::::0;;86757:96::o;42138:161::-;42214:45;42230:7;831:10;42253:5;42214:15;:45::i;:::-;42270:21;42276:7;42285:5;42270;:21::i;:::-;42138:161;;:::o;85416:690::-;2362:13;:11;:13::i;:::-;85496:1:::1;85484:9;:13;85476:36;;;::::0;-1:-1:-1;;;85476:36:0;;7034:2:1;85476:36:0::1;::::0;::::1;7016:21:1::0;7073:2;7053:18;;;7046:30;-1:-1:-1;;;7092:18:1;;;7085:40;7142:18;;85476:36:0::1;6832:334:1::0;85476:36:0::1;85531:10;::::0;:15;85523:40:::1;;;::::0;-1:-1:-1;;;85523:40:0;;7373:2:1;85523:40:0::1;::::0;::::1;7355:21:1::0;7412:2;7392:18;;;7385:30;-1:-1:-1;;;7431:18:1;;;7424:42;7483:18;;85523:40:0::1;7171:336:1::0;85523:40:0::1;85630:12;85617:10;:25:::0;85718:3:::1;85702:13;17060:12:::0;;;16981:99;85702:13:::1;:19;;;;:::i;:::-;85690:9;:31:::0;85785:15:::1;85803:24;85821:4;85803:9;:24::i;:::-;85785:42;;85889:49;85906:4;71452:42;85930:7;85889:8;:49::i;:::-;85999:99;::::0;-1:-1:-1;;;85999:99:0;;86048:4:::1;85999:99;::::0;::::1;8075:34:1::0;8125:18;;;8118:34;;;86064:1:0::1;8168:18:1::0;;;8161:34;;;8211:18;;;8204:34;86070:10:0::1;8254:19:1::0;;;8247:44;86082:15:0::1;8307:19:1::0;;;8300:35;71452:42:0::1;::::0;85999:22:::1;::::0;86029:9:::1;::::0;8009:19:1;;85999:99:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;85465:641;85416:690::o:0;80014:413::-;80061:7;80085:17;;80106:1;80085:22;80081:36;;-1:-1:-1;80116:1:0;;80014:413::o;80081:36::-;80132:19;;80155:1;80132:24;80128:38;;-1:-1:-1;80165:1:0;;80014:413::o;80128:38::-;80179:15;80197;:13;:15::i;:::-;80179:33;;80229:7;80240:1;80229:12;80225:26;;80250:1;80243:8;;;80014:413;:::o;80225:26::-;80264:15;80343:17;;80328:12;:32;;;;:::i;:::-;80305:19;;:56;;;;:::i;:::-;80282:19;;:80;;;;:::i;:::-;80264:98;;80392:7;80382;:17;:37;;80412:7;80382:37;;;80402:7;80382:37;80375:44;;;;80014:413;:::o;82679:937::-;82747:11;;82762:1;82747:16;82743:29;;82679:937;:::o;82743:29::-;82855:26;82884:16;:14;:16::i;:::-;82855:45;-1:-1:-1;83013:21:0;83051:12;;83047:128;;83102:61;83129:4;83136:8;83146:16;83102:18;:61::i;:::-;83080:83;;;;:::i;:::-;;;83047:128;83225:18;83247:1;83225:23;83221:36;;83250:7;;82679:937;:::o;83221:36::-;83368:11;;72362:4;83319:33;83340:12;83319:18;:33;:::i;:::-;:45;;;;:::i;:::-;83318:61;;;;:::i;:::-;83301:13;;:78;;;;;;;:::i;:::-;;;;;;;;83416:18;83390:22;;:44;;;;;;;:::i;:::-;;;;-1:-1:-1;;83504:1:0;83482:19;:23;83536:12;83516:17;:32;83566:42;;1949:25:1;;;83577:10:0;;83566:42;;1937:2:1;1922:18;83566:42:0;;;;;;;82732:884;;82679:937;:::o;81704:158::-;81748:30;81767:10;81748:18;:30::i;:::-;81799:10;81813:5;81791:19;;;:7;:19;;;;;;;;;:27;;-1:-1:-1;;81791:27:0;;;81836:18;;3242:51:1;;;81836:18:0;;3215::1;81836::0;;;;;;;;81704:158::o;78071:316::-;78121:7;78141:20;78172:14;78189:18;:9;:16;:18::i;:::-;78172:35;;78225:9;78220:112;78244:6;78240:1;:10;78220:112;;;78288:32;78304:15;:9;78317:1;78304:12;:15::i;:::-;-1:-1:-1;;;;;17235:18:0;17208:7;17235:18;;;:9;:18;;;;;;;17143:118;78288:32;78272:48;;;;:::i;:::-;;-1:-1:-1;78252:3:0;;78220:112;;;;78367:12;78351:13;17060:12;;;16981:99;78351:13;:28;;;;:::i;16089:95::-;16136:13;16169:7;16162:14;;;;;:::i;17466:182::-;17535:4;831:10;17591:27;831:10;17608:2;17612:5;17591:9;:27::i;79458:213::-;79504:7;79524:21;79573:18;;79548:22;;:43;;;;:::i;:::-;79611:36;;-1:-1:-1;;;79611:36:0;;79641:4;79611:36;;;3242:51:1;79524:67:0;;-1:-1:-1;79524:67:0;;71562:42;;79611:21;;3215:18:1;;79611:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:52;;;;:::i;:::-;79604:59;;;79458:213;:::o;79142:118::-;79191:7;79236:16;:14;:16::i;:::-;79218:15;:13;:15::i;:::-;:34;;;;:::i;:::-;79211:41;;79142:118;:::o;86370:156::-;76226:8;;-1:-1:-1;;;;;76226:8:0;76212:10;:22;76204:44;;;;-1:-1:-1;;;76204:44:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;86451:23:0;::::1;86459:1;86451:23:::0;86443:44:::1;;;::::0;-1:-1:-1;;;86443:44:0;;9165:2:1;86443:44:0::1;::::0;::::1;9147:21:1::0;9204:1;9184:18;;;9177:29;-1:-1:-1;;;9222:18:1;;;9215:38;9270:18;;86443:44:0::1;8963:331:1::0;86443:44:0::1;86498:8;:20:::0;;-1:-1:-1;;;;;;86498:20:0::1;-1:-1:-1::0;;;;;86498:20:0;;;::::1;::::0;;;::::1;::::0;;86370:156::o;84372:162::-;2362:13;:11;:13::i;:::-;84456:10:::1;::::0;:15;84448:40:::1;;;::::0;-1:-1:-1;;;84448:40:0;;7373:2:1;84448:40:0::1;::::0;::::1;7355:21:1::0;7412:2;7392:18;;;7385:30;-1:-1:-1;;;7431:18:1;;;7424:42;7483:18;;84448:40:0::1;7171:336:1::0;84448:40:0::1;84501:25;::::0;-1:-1:-1;;;84501:25:0;;-1:-1:-1;;;;;9491:32:1;;84501:25:0::1;::::0;::::1;9473:51:1::0;9540:18;;;9533:34;;;84501:4:0::1;::::0;:13:::1;::::0;9446:18:1;;84501:25:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;84372:162:::0;;:::o;84582:370::-;2362:13;:11;:13::i;:::-;75202:4:::1;84691:21;::::0;::::1;;;84683:41;;;::::0;-1:-1:-1;;;84683:41:0;;10062:2:1;84683:41:0::1;::::0;::::1;10044:21:1::0;10101:1;10081:18;;;10074:29;-1:-1:-1;;;10119:18:1;;;10112:37;10166:18;;84683:41:0::1;9860:330:1::0;84683:41:0::1;75202:4;84743:22;::::0;::::1;;;84735:43;;;::::0;-1:-1:-1;;;84735:43:0;;10397:2:1;84735:43:0::1;::::0;::::1;10379:21:1::0;10436:1;10416:18;;;10409:29;-1:-1:-1;;;10454:18:1;;;10447:38;10502:18;;84735:43:0::1;10195:331:1::0;84735:43:0::1;75254:5;84797:32;::::0;::::1;;;84789:58;;;::::0;-1:-1:-1;;;84789:58:0;;10733:2:1;84789:58:0::1;::::0;::::1;10715:21:1::0;10772:2;10752:18;;;10745:30;-1:-1:-1;;;10791:18:1;;;10784:43;10844:18;;84789:58:0::1;10531:337:1::0;84789:58:0::1;84860:6;:16:::0;;-1:-1:-1;;84887:18:0;84860:16;::::1;::::0;;::::1;;-1:-1:-1::0;;84887:18:0;;-1:-1:-1;;;84887:18:0;;::::1;::::0;;;::::1;::::0;;;::::1;-1:-1:-1::0;;;;84916:28:0::1;-1:-1:-1::0;;;84916:28:0;;;::::1;;::::0;;;::::1;::::0;;84582:370::o;81451:154::-;81494:29;81512:10;81494:17;:29::i;:::-;81544:10;81536:19;;;;:7;:19;;;;;;;;;:26;;-1:-1:-1;;81536:26:0;81558:4;81536:26;;;81580:17;;3242:51:1;;;81580:17:0;;3215:18:1;81580:17:0;3096:203:1;87003:237:0;76226:8;;-1:-1:-1;;;;;76226:8:0;76212:10;:22;76204:44;;;;-1:-1:-1;;;76204:44:0;;;;;;;:::i;:::-;87120:16:::1;:14;:16::i;:::-;87098:19;:38:::0;87147:19:::1;:42:::0;87220:12:::1;87200:17;:32:::0;87003:237::o;82002:543::-;82108:16;82127:24;82145:4;82127:9;:24::i;:::-;82108:43;;82168:8;82180:1;82168:13;82164:26;;82183:7;82002:543;:::o;82164:26::-;82231:20;82254:56;82280:4;82287:8;82297:12;82254:17;:56::i;:::-;82400:12;;82231:79;;-1:-1:-1;82358:23:0;;75306:5;;82385:27;;-1:-1:-1;;;82400:12:0;;82384:46;82400:12;82231:79;82385:27;:::i;:::-;82384:46;;;;:::i;:::-;82358:72;-1:-1:-1;82447:19:0;;82443:95;;82491:8;;82483:43;;-1:-1:-1;;;;;82491:8:0;;;;82483:43;;;;;82510:15;;82491:8;82483:43;82491:8;82483:43;82510:15;82491:8;82483:43;;;;;;;;;;;;;;;;;;;;;82057:488;;;82002:543;:::o;86597:97::-;76226:8;;-1:-1:-1;;;;;76226:8:0;76212:10;:22;76204:44;;;;-1:-1:-1;;;76204:44:0;;;;;;;:::i;:::-;-1:-1:-1;;86657:9:0::1;:29:::0;86597:97::o;87626:101::-;76226:8;;-1:-1:-1;;;;;76226:8:0;76212:10;:22;76204:44;;;;-1:-1:-1;;;76204:44:0;;;;;;;:::i;:::-;87718:1:::1;87696:19;:23:::0;87626:101::o;3409:220::-;2362:13;:11;:13::i;:::-;-1:-1:-1;;;;;3494:22:0;::::1;3490:93;;3540:31;::::0;-1:-1:-1;;;3540:31:0;;3568:1:::1;3540:31;::::0;::::1;3242:51:1::0;3215:18;;3540:31:0::1;3096:203:1::0;3490:93:0::1;3593:28;3612:8;3593:18;:28::i;77725:114::-:0;77783:4;77807:24;:9;77826:4;77807:18;:24::i;36684:162::-;36794:43;;;-1:-1:-1;;;;;9491:32:1;;36794:43:0;;;9473:51:1;9540:18;;;;9533:34;;;36794:43:0;;;;;;;;;;9446:18:1;;;;36794:43:0;;;;;;;;-1:-1:-1;;;;;36794:43:0;-1:-1:-1;;;36794:43:0;;;36767:71;;36787:5;;36767:19;:71::i;22999:130::-;23084:37;23093:5;23100:7;23109:5;23116:4;23084:8;:37::i;44736:315::-;44034:1;44865:7;;:18;44861:88;;44907:30;;-1:-1:-1;;;44907:30:0;;;;;;;;;;;44861:88;44034:1;45026:7;:17;44736:315::o;92128:188::-;92201:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92183:15;;92201:22;;:15;:22::i;:::-;92236:12;;;:22;-1:-1:-1;92295:13:0;;92269:23;;;;:39;92128:188::o;24715:487::-;-1:-1:-1;;;;;17818:18:0;;;24815:24;17818:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;-1:-1:-1;;24882:37:0;;24878:317;;24959:5;24940:16;:24;24936:132;;;24992:60;;-1:-1:-1;;;24992:60:0;;-1:-1:-1;;;;;11093:32:1;;24992:60:0;;;11075:51:1;11142:18;;;11135:34;;;11185:18;;;11178:34;;;11048:18;;24992:60:0;10873:345:1;24936:132:0;25111:57;25120:5;25127:7;25155:5;25136:16;:24;25162:5;25111:8;:57::i;19574:308::-;-1:-1:-1;;;;;19658:18:0;;19654:88;;19700:30;;-1:-1:-1;;;19700:30:0;;19727:1;19700:30;;;3242:51:1;3215:18;;19700:30:0;3096:203:1;19654:88:0;-1:-1:-1;;;;;19756:16:0;;19752:88;;19796:32;;-1:-1:-1;;;19796:32:0;;19825:1;19796:32;;;3242:51:1;3215:18;;19796:32:0;3096:203:1;19752:88:0;19850:24;19858:4;19864:2;19868:5;19850:7;:24::i;91787:270::-;91854:7;91874:13;91906:5;:23;;;91890:13;;:39;;;;:::i;:::-;91874:55;-1:-1:-1;91940:14:0;91983:24;72362:4;91983:12;:24;:::i;:::-;91958:12;;:20;;91973:5;;91958:20;:::i;:::-;91957:51;;;;:::i;:::-;91940:68;;92043:6;92028:5;:12;;;:21;;;;:::i;:::-;92021:28;91787:270;-1:-1:-1;;;;91787:270:0:o;22235:211::-;-1:-1:-1;;;;;22306:21:0;;22302:91;;22351:30;;-1:-1:-1;;;22351:30:0;;22378:1;22351:30;;;3242:51:1;3215:18;;22351:30:0;3096:203:1;22302:91:0;22403:35;22411:7;22428:1;22432:5;22403:7;:35::i;2641:166::-;2522:7;2549:6;-1:-1:-1;;;;;2549:6:0;831:10;2701:23;2697:103;;2748:40;;-1:-1:-1;;;2748:40:0;;831:10;2748:40;;;3242:51:1;3215:18;;2748:40:0;3096:203:1;90126:172:0;90189:23;90207:4;90189:17;:23::i;:::-;90225:22;:9;90242:4;90225:16;:22::i;:::-;-1:-1:-1;90265:25:0;;-1:-1:-1;;;;;3260:32:1;;3242:51;;90265:25:0;;3230:2:1;3215:18;90265:25:0;;;;;;;;90126:172;:::o;87994:121::-;88097:10;;88084;;88045:4;;88084:23;;88097:10;;;;;88084:23;:::i;:::-;88069:12;:38;88062:45;;87994:121;:::o;3789:191::-;3863:16;3882:6;;-1:-1:-1;;;;;3899:17:0;;;-1:-1:-1;;;;;;3899:17:0;;;;;;3932:40;;3882:6;;;;;;;3932:40;;3863:16;3932:40;3852:128;3789:191;:::o;96127:783::-;96228:7;96293:8;96305:1;96293:13;96289:27;;-1:-1:-1;96315:1:0;96308:8;;96289:27;96367:48;96418:341;;;;;;;;71452:42;-1:-1:-1;;;;;96477:11:0;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;96418:341:0;;;;;71562:42;96418:341;;;;;;;;96555:7;;;;;;;;;96418:341;;;;;;;;;;;;;;;;;;;96615:15;96418:341;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;96418:341:0;;;;;96850:52;;-1:-1:-1;;;96850:52:0;;11774:13:1;;11770:22;;96850:52:0;;;11752:41:1;11841:17;;;11835:24;11831:33;;11809:20;;;11802:63;11913:17;;;11907:24;11903:39;;;11881:20;;;11874:69;11991:17;;;11985:24;11981:33;;11959:20;;;11952:63;12059:17;;12053:24;12031:20;;;12024:54;12122:17;;;12116:24;12094:20;;;12087:54;12185:17;;12179:24;12157:20;;;12150:54;12252:17;;;12246:24;12242:33;12220:20;;;12213:63;96367:392:0;;-1:-1:-1;71339:42:0;;96850:27;;96418:341;;11686:19:1;;96850:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;96843:59;96127:783;-1:-1:-1;;;;;96127:783:0:o;91168:437::-;91287:28;91310:4;91287:22;:28::i;:::-;91283:41;;;91168:437;:::o;91283:41::-;-1:-1:-1;;;;;17235:18:0;;17208:7;17235:18;;;:9;:18;;;;;;91369:11;;:36;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;91525:18:0;;91503:19;91525:18;;;:12;:18;;;;;91556:12;91525:18;91556:5;:12::i;:::-;91596:1;91581:16;;-1:-1:-1;91168:437:0:o;54893:117::-;54956:7;54983:19;54991:3;50193:18;;50110:109;55364:158;55438:7;55489:22;55493:3;55505:5;55489:3;:22::i;90505:459::-;90624:28;90647:4;90624:22;:28::i;:::-;90619:42;;90505:459;:::o;90619:42::-;-1:-1:-1;;;;;17235:18:0;;90706:15;17235:18;;;:9;:18;;;;;;90706:39;;90773:7;90758:11;;:22;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;90853:18:0;;;90831:19;90853:18;;;:12;:18;;;;;90884:22;;;90943:13;;90917:23;;;;:39;90505:459::o;95305:708::-;95401:7;95466:8;95478:1;95466:13;95462:27;;-1:-1:-1;95488:1:0;95481:8;;95462:27;95546:50;95563:4;71452:42;95587:8;95546;:50::i;:::-;95675:16;;;95689:1;95675:16;;;;;;;;95651:21;;95675:16;;;;;;;;;;-1:-1:-1;95675:16:0;95651:40;;95720:4;95702;95707:1;95702:7;;;;;;;;:::i;:::-;;;;;;:23;-1:-1:-1;;;;;95702:23:0;;;-1:-1:-1;;;;;95702:23:0;;;;;71452:42;-1:-1:-1;;;;;95746:11:0;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95736:4;95741:1;95736:7;;;;;;;;:::i;:::-;-1:-1:-1;;;;;95736:23:0;;;:7;;;;;;;;;;;:23;95835:108;;-1:-1:-1;;;95835:108:0;;95801:21;;71452:42;;95835:57;;:108;;95893:8;;95903:12;;95917:4;;95923:2;;95927:15;;95835:108;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95987:18;95963:21;:42;;;;:::i;:::-;95956:49;95305:708;-1:-1:-1;;;;;;95305:708:0:o;54640:167::-;-1:-1:-1;;;;;54774:23:0;;54720:4;49990:21;;;:14;;;:21;;;;;;:26;;54744:55;49893:131;39495:638;39919:23;39945:33;-1:-1:-1;;;;;39945:27:0;;39973:4;39945:27;:33::i;:::-;39919:59;;39993:10;:17;40014:1;39993:22;;:57;;;;;40031:10;40020:30;;;;;;;;;;;;:::i;:::-;40019:31;39993:57;39989:137;;;40074:40;;-1:-1:-1;;;40074:40:0;;-1:-1:-1;;;;;3260:32:1;;40074:40:0;;;3242:51:1;3215:18;;40074:40:0;3096:203:1;23980:443:0;-1:-1:-1;;;;;24093:19:0;;24089:91;;24136:32;;-1:-1:-1;;;24136:32:0;;24165:1;24136:32;;;3242:51:1;3215:18;;24136:32:0;3096:203:1;24089:91:0;-1:-1:-1;;;;;24194:21:0;;24190:92;;24239:31;;-1:-1:-1;;;24239:31:0;;24267:1;24239:31;;;3242:51:1;3215:18;;24239:31:0;3096:203:1;24190:92:0;-1:-1:-1;;;;;24292:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;:35;;;24338:78;;;;24389:7;-1:-1:-1;;;;;24373:31:0;24382:5;-1:-1:-1;;;;;24373:31:0;;24398:5;24373:31;;;;1949:25:1;;1937:2;1922:18;;1803:177;24373:31:0;;;;;;;;23980:443;;;;:::o;92896:1721::-;93025:21;93049:19;:17;:19::i;:::-;93025:43;;93126:15;93161:4;-1:-1:-1;;;;;93144:21:0;93152:4;-1:-1:-1;;;;;93144:21:0;;:50;;;;;93170:24;93191:2;93170:20;:24::i;:::-;93169:25;93144:50;93126:68;;93205:16;93225:26;93246:4;93225:20;:26::i;:::-;93224:27;:50;;;;;93272:2;-1:-1:-1;;;;;93255:19:0;93263:4;-1:-1:-1;;;;;93255:19:0;;93224:50;93205:69;;93357:16;:39;;;;;93377:19;93391:4;93377:13;:19::i;:::-;93353:88;;;93413:16;;-1:-1:-1;;;93413:16:0;;13730:2:1;93413:16:0;;;13712:21:1;13769:1;13749:18;;;13742:29;-1:-1:-1;;;13787:18:1;;;13780:36;13833:18;;93413:16:0;13528:329:1;93353:88:0;93502:11;93545;:25;;93569:1;93545:25;;;93559:7;;-1:-1:-1;;;93559:7:0;;;;93545:25;93517:10;:23;;93539:1;93517:23;;;93530:6;;;;;;;93517:23;93516:55;;;;:::i;:::-;93502:69;;;-1:-1:-1;93584:17:0;75306:5;93605:12;93502:69;93605:6;:12;:::i;:::-;93604:31;;;;:::i;:::-;93584:51;-1:-1:-1;93648:28:0;93679:18;93584:51;93679:6;:18;:::i;:::-;93648:49;-1:-1:-1;93761:13:0;;93757:91;;93791:45;93805:4;93819;93826:9;93791:13;:45::i;:::-;93916:11;93912:63;;;93944:19;93961:1;93944:16;:19::i;:::-;94048:45;94062:4;94068:2;94072:20;94048:13;:45::i;:::-;94167:18;94180:4;94167:12;:18::i;:::-;94196:16;94209:2;94196:12;:16::i;:::-;94315;94314:17;:50;;;;;94336:28;94361:2;94336:24;:28::i;:::-;94335:29;94314:50;94310:102;;;94381:19;94397:2;94381:15;:19::i;:::-;94504:28;94529:2;94504:24;:28::i;:::-;94499:111;;94574:9;;94557:13;94567:2;94557:9;:13::i;:::-;:26;;94549:49;;;;-1:-1:-1;;;94549:49:0;;14239:2:1;94549:49:0;;;14221:21:1;14278:2;14258:18;;;14251:30;-1:-1:-1;;;14297:18:1;;;14290:40;14347:18;;94549:49:0;14037:334:1;94549:49:0;92973:1644;;;;;;92896:1721;;;:::o;54396:158::-;54469:4;54493:53;54501:3;-1:-1:-1;;;;;54521:23:0;;54493:7;:53::i;89544:277::-;89612:4;-1:-1:-1;;;;;89636:18:0;;;;:43;;-1:-1:-1;89666:4:0;-1:-1:-1;;;;;89658:21:0;;;89636:43;:87;;;;89703:1;89684:4;-1:-1:-1;;;;;89684:16:0;;:20;:38;;;;-1:-1:-1;;;;;;89709:13:0;;;;;;:7;:13;;;;;;;;89708:14;89684:38;89636:123;;;;89740:19;89754:4;89740:13;:19::i;:::-;89636:177;;;-1:-1:-1;;;;;;;89763:50:0;:42;:50;;89544:277::o;50573:120::-;50640:7;50667:3;:11;;50679:5;50667:18;;;;;;;;:::i;:::-;;;;;;;;;50660:25;;50573:120;;;;:::o;31999:153::-;32074:12;32106:38;32128:6;32136:4;32142:1;32106:21;:38::i;88926:146::-;88992:4;89024;-1:-1:-1;;;;;89016:21:0;;;;:48;;-1:-1:-1;;;;;;;89041:23:0;71452:42;89041:23;;88926:146::o;20206:1135::-;-1:-1:-1;;;;;20296:18:0;;20292:552;;20450:5;20434:12;;:21;;;;;;;:::i;:::-;;;;-1:-1:-1;20292:552:0;;-1:-1:-1;20292:552:0;;-1:-1:-1;;;;;20510:15:0;;20488:19;20510:15;;;:9;:15;;;;;;20544:19;;;20540:117;;;20591:50;;-1:-1:-1;;;20591:50:0;;-1:-1:-1;;;;;11093:32:1;;20591:50:0;;;11075:51:1;11142:18;;;11135:34;;;11185:18;;;11178:34;;;11048:18;;20591:50:0;10873:345:1;20540:117:0;-1:-1:-1;;;;;20780:15:0;;;;;;:9;:15;;;;;20798:19;;;;20780:37;;20292:552;-1:-1:-1;;;;;20860:16:0;;20856:435;;21026:12;:21;;;;;;;20856:435;;;-1:-1:-1;;;;;21242:13:0;;;;;;:9;:13;;;;;:22;;;;;;20856:435;21323:2;-1:-1:-1;;;;;21308:25:0;21317:4;-1:-1:-1;;;;;21308:25:0;;21327:5;21308:25;;;;1949::1;;1937:2;1922:18;;1803:177;21308:25:0;;;;;;;;20206:1135;;;:::o;94869:325::-;94928:28;94951:4;94928:22;:28::i;:::-;94924:41;;;94869:325;:::o;94924:41::-;94977:15;94995;95005:4;94995:9;:15::i;:::-;-1:-1:-1;;;;;95045:18:0;;95023:19;95045:18;;;:12;:18;;;;;95104:12;;95090:11;;94977:33;;-1:-1:-1;95045:18:0;;94977:33;;95090:26;;;:::i;:::-;:36;;;;:::i;:::-;95076:11;:50;95139:12;95145:5;95139;:12::i;:::-;95164:22;-1:-1:-1;94869:325:0:o;88282:175::-;88352:4;88384;-1:-1:-1;;;;;88376:21:0;;;;:48;;-1:-1:-1;71452:42:0;-1:-1:-1;;;;;88401:23:0;;;88376:48;:73;;;-1:-1:-1;;88436:4:0;-1:-1:-1;;;;;88428:21:0;;;;;;;88282:175::o;89891:160::-;89949:24;89968:4;89949:18;:24::i;:::-;89986:19;:9;90000:4;89986:13;:19::i;:::-;-1:-1:-1;90023:20:0;;-1:-1:-1;;;;;3260:32:1;;3242:51;;90023:20:0;;3230:2:1;3215:18;90023:20:0;3096:203:1;88645:198:0;88715:4;88747;-1:-1:-1;;;;;88739:21:0;;;;:48;;-1:-1:-1;71452:42:0;-1:-1:-1;;;;;88764:23:0;;;88739:48;:73;;;;88808:4;-1:-1:-1;;;;;88791:21:0;88799:4;-1:-1:-1;;;;;88791:21:0;;88739:73;:96;;;;88816:19;88830:4;88816:13;:19::i;48407:1400::-;48473:4;48604:21;;;:14;;;:21;;;;;;48642:13;;48638:1162;;49015:18;49036:12;49047:1;49036:8;:12;:::i;:::-;49083:18;;49015:33;;-1:-1:-1;49063:17:0;;49083:22;;49104:1;;49083:22;:::i;:::-;49063:42;;49140:9;49126:10;:23;49122:385;;49170:17;49190:3;:11;;49202:9;49190:22;;;;;;;;:::i;:::-;;;;;;;;;49170:42;;49340:9;49314:3;:11;;49326:10;49314:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;49455:25;;;:14;;;:25;;;;;:36;;;49122:385;49588:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;49694:3;:14;;:21;49709:5;49694:21;;;;;;;;;;;49687:28;;;49739:4;49732:11;;;;;;;48638:1162;49783:5;49776:12;;;;;48638:1162;48479:1328;48407:1400;;;;:::o;32487:398::-;32586:12;32639:5;32615:21;:29;32611:110;;;32668:41;;-1:-1:-1;;;32668:41:0;;32703:4;32668:41;;;3242:51:1;3215:18;;32668:41:0;3096:203:1;32611:110:0;32732:12;32746:23;32773:6;-1:-1:-1;;;;;32773:11:0;32792:5;32799:4;32773:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;32731:73;;;;32822:55;32849:6;32857:7;32866:10;32822:26;:55::i;54068:152::-;54138:4;54162:50;54167:3;-1:-1:-1;;;;;54187:23:0;;54162:4;:50::i;33963:597::-;34111:12;34141:7;34136:417;;34165:19;34173:10;34165:7;:19::i;:::-;34136:417;;;34393:17;;:22;:49;;;;-1:-1:-1;;;;;;34419:18:0;;;:23;34393:49;34389:121;;;34470:24;;-1:-1:-1;;;34470:24:0;;-1:-1:-1;;;;;3260:32:1;;34470:24:0;;;3242:51:1;3215:18;;34470:24:0;3096:203:1;34389:121:0;-1:-1:-1;34531:10:0;34524:17;;47815:416;47878:4;49990:21;;;:14;;;:21;;;;;;47895:329;;-1:-1:-1;47938:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;48123:18;;48099:21;;;:14;;;:21;;;;;;:42;;;;48156:11;;47895:329;-1:-1:-1;48207:5:0;48200:12;;35113:528;35246:17;;:21;35242:392;;35478:10;35472:17;35535:15;35522:10;35518:2;35514:19;35507:44;35242:392;35605:17;;-1:-1:-1;;;35605:17:0;;;;;;;;;;;14:139:1;-1:-1:-1;;;;;97:31:1;;87:42;;77:70;;143:1;140;133:12;158:269;231:6;284:2;272:9;263:7;259:23;255:32;252:52;;;300:1;297;290:12;252:52;339:9;326:23;358:39;391:5;358:39;:::i;432:250::-;517:1;527:113;541:6;538:1;535:13;527:113;;;617:11;;;611:18;598:11;;;591:39;563:2;556:10;527:113;;;-1:-1:-1;;674:1:1;656:16;;649:27;432:250::o;687:396::-;836:2;825:9;818:21;799:4;868:6;862:13;911:6;906:2;895:9;891:18;884:34;927:79;999:6;994:2;983:9;979:18;974:2;966:6;962:15;927:79;:::i;:::-;1067:2;1046:15;-1:-1:-1;;1042:29:1;1027:45;;;;1074:2;1023:54;;687:396;-1:-1:-1;;687:396:1:o;1283:323::-;1351:6;1359;1412:2;1400:9;1391:7;1387:23;1383:32;1380:52;;;1428:1;1425;1418:12;1380:52;1467:9;1454:23;1486:39;1519:5;1486:39;:::i;:::-;1544:5;1596:2;1581:18;;;;1568:32;;-1:-1:-1;;;1283:323:1:o;2245:472::-;2322:6;2330;2338;2391:2;2379:9;2370:7;2366:23;2362:32;2359:52;;;2407:1;2404;2397:12;2359:52;2446:9;2433:23;2465:39;2498:5;2465:39;:::i;:::-;2523:5;-1:-1:-1;2580:2:1;2565:18;;2552:32;2593:41;2552:32;2593:41;:::i;:::-;2245:472;;2653:7;;-1:-1:-1;;;2707:2:1;2692:18;;;;2679:32;;2245:472::o;2911:180::-;2970:6;3023:2;3011:9;3002:7;2998:23;2994:32;2991:52;;;3039:1;3036;3029:12;2991:52;-1:-1:-1;3062:23:1;;2911:180;-1:-1:-1;2911:180:1:o;3304:161::-;3371:20;;3431:8;3420:20;;3410:31;;3400:59;;3455:1;3452;3445:12;3400:59;3304:161;;;:::o;3470:184::-;3528:6;3581:2;3569:9;3560:7;3556:23;3552:32;3549:52;;;3597:1;3594;3587:12;3549:52;3620:28;3638:9;3620:28;:::i;4118:328::-;4192:6;4200;4208;4261:2;4249:9;4240:7;4236:23;4232:32;4229:52;;;4277:1;4274;4267:12;4229:52;4300:28;4318:9;4300:28;:::i;:::-;4290:38;;4347:37;4380:2;4369:9;4365:18;4347:37;:::i;:::-;4337:47;;4403:37;4436:2;4425:9;4421:18;4403:37;:::i;:::-;4393:47;;4118:328;;;;;:::o;4451:404::-;4519:6;4527;4580:2;4568:9;4559:7;4555:23;4551:32;4548:52;;;4596:1;4593;4586:12;4548:52;4635:9;4622:23;4654:39;4687:5;4654:39;:::i;:::-;4712:5;-1:-1:-1;4769:2:1;4754:18;;4741:32;4782:41;4741:32;4782:41;:::i;:::-;4842:7;4832:17;;;4451:404;;;;;:::o;5659:184::-;5729:6;5782:2;5770:9;5761:7;5757:23;5753:32;5750:52;;;5798:1;5795;5788:12;5750:52;-1:-1:-1;5821:16:1;;5659:184;-1:-1:-1;5659:184:1:o;5848:380::-;5927:1;5923:12;;;;5970;;;5991:61;;6045:4;6037:6;6033:17;6023:27;;5991:61;6098:2;6090:6;6087:14;6067:18;6064:38;6061:161;;6144:10;6139:3;6135:20;6132:1;6125:31;6179:4;6176:1;6169:15;6207:4;6204:1;6197:15;6061:161;;5848:380;;;:::o;6233:127::-;6294:10;6289:3;6285:20;6282:1;6275:31;6325:4;6322:1;6315:15;6349:4;6346:1;6339:15;6365:125;6430:9;;;6451:10;;;6448:36;;;6464:18;;:::i;6495:332::-;6697:2;6679:21;;;6736:1;6716:18;;;6709:29;-1:-1:-1;;;6769:2:1;6754:18;;6747:39;6818:2;6803:18;;6495:332::o;7512:217::-;7552:1;7578;7568:132;;7622:10;7617:3;7613:20;7610:1;7603:31;7657:4;7654:1;7647:15;7685:4;7682:1;7675:15;7568:132;-1:-1:-1;7714:9:1;;7512:217::o;8346:306::-;8434:6;8442;8450;8503:2;8491:9;8482:7;8478:23;8474:32;8471:52;;;8519:1;8516;8509:12;8471:52;8548:9;8542:16;8532:26;;8598:2;8587:9;8583:18;8577:25;8567:35;;8642:2;8631:9;8627:18;8621:25;8611:35;;8346:306;;;;;:::o;8657:128::-;8724:9;;;8745:11;;;8742:37;;;8759:18;;:::i;8790:168::-;8863:9;;;8894;;8911:15;;;8905:22;;8891:37;8881:71;;8932:18;;:::i;9578:277::-;9645:6;9698:2;9686:9;9677:7;9673:23;9669:32;9666:52;;;9714:1;9711;9704:12;9666:52;9746:9;9740:16;9799:5;9792:13;9785:21;9778:5;9775:32;9765:60;;9821:1;9818;9811:12;11223:259;11293:6;11346:2;11334:9;11325:7;11321:23;11317:32;11314:52;;;11362:1;11359;11352:12;11314:52;11394:9;11388:16;11413:39;11446:5;11413:39;:::i;12419:127::-;12480:10;12475:3;12471:20;12468:1;12461:31;12511:4;12508:1;12501:15;12535:4;12532:1;12525:15;12551:972;12805:4;12853:3;12842:9;12838:19;12884:6;12873:9;12866:25;12910:2;12948:6;12943:2;12932:9;12928:18;12921:34;12991:3;12986:2;12975:9;12971:18;12964:31;13015:6;13050;13044:13;13081:6;13073;13066:22;13119:3;13108:9;13104:19;13097:26;;13158:2;13150:6;13146:15;13132:29;;13179:1;13189:195;13203:6;13200:1;13197:13;13189:195;;;13268:13;;-1:-1:-1;;;;;13264:39:1;13252:52;;13359:15;;;;13324:12;;;;13300:1;13218:9;13189:195;;;-1:-1:-1;;;;;;;13440:32:1;;;;13435:2;13420:18;;13413:60;-1:-1:-1;;;13504:3:1;13489:19;13482:35;13401:3;12551:972;-1:-1:-1;;;12551:972:1:o;13862:170::-;13929:8;13957:10;;;13969;;;13953:27;;13992:11;;;13989:37;;;14006:18;;:::i;14376:127::-;14437:10;14432:3;14428:20;14425:1;14418:31;14468:4;14465:1;14458:15;14492:4;14489:1;14482:15;14508:287;14637:3;14675:6;14669:13;14691:66;14750:6;14745:3;14738:4;14730:6;14726:17;14691:66;:::i;:::-;14773:16;;;;;14508:287;-1:-1:-1;;14508:287:1:o

Swarm Source

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