ETH Price: $3,262.29 (+2.75%)
Gas: 4 Gwei

Token

HER Coin (HER)
 

Overview

Max Total Supply

69,420,000 HER

Holders

188

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

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

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

Contract Source Code Verified (Exact Match)

Contract Name:
HERCoin

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, Unlicense license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-12-05
*/

// SPDX-License-Identifier: UNLICENSED
// File: PoolAddress.sol


pragma solidity >=0.5.0;

/// @title Provides functions for deriving a pool address from the factory, tokens, and the fee
library PoolAddress {
    bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;

    /// @notice The identifying key of the pool
    struct PoolKey {
        address token0;
        address token1;
        uint24 fee;
    }

    /// @notice Returns PoolKey: the ordered tokens with the matched fee levels
    /// @param tokenA The first token of a pool, unsorted
    /// @param tokenB The second token of a pool, unsorted
    /// @param fee The fee level of the pool
    /// @return Poolkey The pool details with ordered token0 and token1 assignments
    function getPoolKey(address tokenA, address tokenB, uint24 fee) internal pure returns (PoolKey memory) {
        if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
        return PoolKey({token0: tokenA, token1: tokenB, fee: fee});
    }

    /// @notice Deterministically computes the pool address given the factory and PoolKey
    /// @param factory The Uniswap V3 factory contract address
    /// @param key The PoolKey
    /// @return pool The contract address of the V3 pool
    function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) {
        require(key.token0 < key.token1);
        pool = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            factory,
                            keccak256(abi.encode(key.token0, key.token1, key.fee)),
                            POOL_INIT_CODE_HASH
                        )
                    )
                )
            )
        );
    }
}
// File: @openzeppelin/contracts/utils/Nonces.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
pragma solidity ^0.8.20;

/**
 * @dev Provides tracking nonces for addresses. Nonces will only increment.
 */
abstract contract Nonces {
    /**
     * @dev The nonce used for an `account` is not the expected current nonce.
     */
    error InvalidAccountNonce(address account, uint256 currentNonce);

    mapping(address account => uint256) private _nonces;

    /**
     * @dev Returns the next unused nonce for an address.
     */
    function nonces(address owner) public view virtual returns (uint256) {
        return _nonces[owner];
    }

    /**
     * @dev Consumes a nonce.
     *
     * Returns the current value and increments nonce.
     */
    function _useNonce(address owner) internal virtual returns (uint256) {
        // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
        // decremented or reset. This guarantees that the nonce never overflows.
        unchecked {
            // It is important to do x++ and not ++x here.
            return _nonces[owner]++;
        }
    }

    /**
     * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
     */
    function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
        uint256 current = _useNonce(owner);
        if (nonce != current) {
            revert InvalidAccountNonce(owner, current);
        }
    }
}

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


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

pragma solidity ^0.8.20;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

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


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

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

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


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

pragma solidity ^0.8.20;


// | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
// | length  | 0x                                                              BB |
type ShortString is bytes32;

/**
 * @dev This library provides functions to convert short memory strings
 * into a `ShortString` type that can be used as an immutable variable.
 *
 * Strings of arbitrary length can be optimized using this library if
 * they are short enough (up to 31 bytes) by packing them with their
 * length (1 byte) in a single EVM word (32 bytes). Additionally, a
 * fallback mechanism can be used for every other case.
 *
 * Usage example:
 *
 * ```solidity
 * contract Named {
 *     using ShortStrings for *;
 *
 *     ShortString private immutable _name;
 *     string private _nameFallback;
 *
 *     constructor(string memory contractName) {
 *         _name = contractName.toShortStringWithFallback(_nameFallback);
 *     }
 *
 *     function name() external view returns (string memory) {
 *         return _name.toStringWithFallback(_nameFallback);
 *     }
 * }
 * ```
 */
library ShortStrings {
    // Used as an identifier for strings longer than 31 bytes.
    bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;

    error StringTooLong(string str);
    error InvalidShortString();

    /**
     * @dev Encode a string of at most 31 chars into a `ShortString`.
     *
     * This will trigger a `StringTooLong` error is the input string is too long.
     */
    function toShortString(string memory str) internal pure returns (ShortString) {
        bytes memory bstr = bytes(str);
        if (bstr.length > 31) {
            revert StringTooLong(str);
        }
        return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
    }

    /**
     * @dev Decode a `ShortString` back to a "normal" string.
     */
    function toString(ShortString sstr) internal pure returns (string memory) {
        uint256 len = byteLength(sstr);
        // using `new string(len)` would work locally but is not memory safe.
        string memory str = new string(32);
        /// @solidity memory-safe-assembly
        assembly {
            mstore(str, len)
            mstore(add(str, 0x20), sstr)
        }
        return str;
    }

    /**
     * @dev Return the length of a `ShortString`.
     */
    function byteLength(ShortString sstr) internal pure returns (uint256) {
        uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
        if (result > 31) {
            revert InvalidShortString();
        }
        return result;
    }

    /**
     * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
     */
    function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
        if (bytes(value).length < 32) {
            return toShortString(value);
        } else {
            StorageSlot.getStringSlot(store).value = value;
            return ShortString.wrap(FALLBACK_SENTINEL);
        }
    }

    /**
     * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     */
    function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return toString(value);
        } else {
            return store;
        }
    }

    /**
     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using
     * {setWithFallback}.
     *
     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
     */
    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return byteLength(value);
        } else {
            return bytes(store).length;
        }
    }
}

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


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

pragma solidity ^0.8.20;

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

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

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

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

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


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

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

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

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

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

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

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

pragma solidity ^0.8.20;



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

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

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

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

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

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

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

// File: @openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol


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

pragma solidity ^0.8.20;


/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

// File: @openzeppelin/contracts/utils/cryptography/EIP712.sol


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

pragma solidity ^0.8.20;




/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
 * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
 * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
 * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable
 */
abstract contract EIP712 is IERC5267 {
    using ShortStrings for *;

    bytes32 private constant TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;
    address private immutable _cachedThis;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    ShortString private immutable _name;
    ShortString private immutable _version;
    string private _nameFallback;
    string private _versionFallback;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _name = name.toShortStringWithFallback(_nameFallback);
        _version = version.toShortStringWithFallback(_versionFallback);
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
        _cachedThis = address(this);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {IERC-5267}.
     */
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _name which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Name() internal view returns (string memory) {
        return _name.toStringWithFallback(_nameFallback);
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _version which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Version() internal view returns (string memory) {
        return _version.toStringWithFallback(_versionFallback);
    }
}

// File: @openzeppelin/contracts/utils/cryptography/ECDSA.sol


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

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

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


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

pragma solidity ^0.8.20;

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

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


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

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

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


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

pragma solidity ^0.8.20;

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

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

// File: @openzeppelin/contracts/access/Ownable.sol


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

pragma solidity ^0.8.20;


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

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


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

pragma solidity ^0.8.20;

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

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


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

pragma solidity ^0.8.20;


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

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


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

pragma solidity ^0.8.20;





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

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


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

pragma solidity ^0.8.20;






/**
 * @dev Implementation 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.
 */
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces {
    bytes32 private constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    /**
     * @dev Permit deadline has expired.
     */
    error ERC2612ExpiredSignature(uint256 deadline);

    /**
     * @dev Mismatched signature.
     */
    error ERC2612InvalidSigner(address signer, address owner);

    /**
     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
     *
     * It's a good idea to use the same `name` that is defined as the ERC20 token name.
     */
    constructor(string memory name) EIP712(name, "1") {}

    /**
     * @inheritdoc IERC20Permit
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        if (block.timestamp > deadline) {
            revert ERC2612ExpiredSignature(deadline);
        }

        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));

        bytes32 hash = _hashTypedDataV4(structHash);

        address signer = ECDSA.recover(hash, v, r, s);
        if (signer != owner) {
            revert ERC2612InvalidSigner(signer, owner);
        }

        _approve(owner, spender, value);
    }

    /**
     * @inheritdoc IERC20Permit
     */
    function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
        return super.nonces(owner);
    }

    /**
     * @inheritdoc IERC20Permit
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
        return _domainSeparatorV4();
    }
}

// File: HerCoin.sol


pragma solidity ^0.8.20;





interface IUniswapRouterV2 {
    function WETH() external pure returns (address);
}

address constant UNISWAP_V2_ROUTER = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
address constant UNISWAP_V2_FACTORY = address(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
address constant UNISWAP_V3_FACTORY = address(0x1F98431c8aD98523631AE4a59f267346ea31F984);

contract HERCoin is ERC20, ERC20Permit, Ownable {
    //------------------------------------------------------------------------------------//
    //                                      errors                                        //
    //------------------------------------------------------------------------------------//
    error MaxHoldingAmountExceeded();
    error ErrNotTokenRedeemer();
    error ErrTotalSupplyExceeded();
    error ErrNotLiquidtyProvider();
    error ErrExceedingMaxAmountInSellOrder();
    error ErrExceedingMaxAmountInBuyOrder();
    error ErrNoSandwhichesHere();
    //------------------------------------------------------------------------------------//
    //                                      constants                                     //
    //------------------------------------------------------------------------------------//

    uint256 public constant TOTAL_SUPPLY = 69_420_000 ether;
    uint256 public constant MAX_HOLDING_AMOUNT_PER_WALLET = TOTAL_SUPPLY * uint256(1) / uint256(100); //3%

    /// @dev adjust these values as needed
    uint256 public constant MAX_BUY_ORDER = TOTAL_SUPPLY * uint256(5) / uint256(1000); //3%

    /// @dev adjust these values as needed
    uint256 public constant MAX_SELL_ORDER = TOTAL_SUPPLY * uint256(5) / uint256(1000); //3

    /// @dev jared from subway address
    address private constant JARED = address(0xae2Fc483527B8EF99EB5D9B44875F005ba1FaE13);

    //------------------------------------------------------------------------------------//
    //                                      immutable                                     //
    //------------------------------------------------------------------------------------//

    /**
     * @notice the primary uniswap(v2) pair for HER
     */
    address public immutable uniswapV2Pair;

    //------------------------------------------------------------------------------------//
    //                                      variables                                     //
    //------------------------------------------------------------------------------------//
    /**
     * @notice the timestamp of when trading opens
     * @dev this is set in the _update override when an LP makes a trade
     */
    uint256 public genesisTimestamp;

    /**
     * @notice the address of the token redeemer
     * @dev
     */
    address public tokenRedeemer = 0x4b2ADfCa850EF1b1a425572F552bb9B35aF63d61;

    /**
     * @notice a boolean indicating if sell and buy limits are on
     * @dev this is set to false when the owner renounces ownership
     */
    bool public limitsOn = false;

    //------------------------------------------------------------------------------------//
    //                                      mappings                                      //
    //------------------------------------------------------------------------------------//

    /// @notice A mapping of pool addresses to a boolean indicating if the pool is registered
    /// @dev only univ2 and univ3 her/weth pools are registered
    mapping(address => AddressData) private _addressData;

    struct AddressData {
        bool isPool;
        bool isExcludedFromTax;
    }
    //------------------------------------------------------------------------------------//
    //                                      constructor                                   //
    //------------------------------------------------------------------------------------//
    /**
     * @notice Constructs the HerToken contract
     * @param _owner The address to set as owner
     */

    constructor(address _owner) payable ERC20("HER Coin", "HER") ERC20Permit("HER Coin") Ownable(_owner) {
        address weth = IUniswapRouterV2(UNISWAP_V2_ROUTER).WETH();
        uniswapV2Pair = pairFor(UNISWAP_V2_FACTORY, address(this), weth);
        _addressData[uniswapV2Pair] = AddressData({isPool: true, isExcludedFromTax: false});
        _addressData[computeUniv3Address(weth, 500)] = AddressData({isPool: true, isExcludedFromTax: false});
        _addressData[computeUniv3Address(weth, 3000)] = AddressData({isPool: true, isExcludedFromTax: false});
        _addressData[computeUniv3Address(weth, 10000)] = AddressData({isPool: true, isExcludedFromTax: false});
        _addressData[_owner] = AddressData({isPool: false, isExcludedFromTax: true});
        _addressData[address(this)] = AddressData({isPool: false, isExcludedFromTax: true});
        _addressData[_owner] = AddressData({isPool: false, isExcludedFromTax: true});
    }

    //------------------------------------------------------------------------------------//
    //                                 ERC20 Overrides                                    //
    //------------------------------------------------------------------------------------//
    /**
     * @dev - overrides ERC20 update for custom logic
     * @dev the restrictions are as follows:
     * 1. If the sender is a registered pool, enforce a tax
     * 2. If the recipient is a registered pool, enforce a tax
     * 3. If limits are on, enforce a max holding amount per wallet
     * @param from The address to transfer from
     * @param to The address to transfer to
     * @param value The amount to transfer
     */
    function _update(address from, address to, uint256 value) internal override(ERC20) {
        bool _limitsOn = limitsOn;
        uint256 _value = value;
        AddressData memory fromData = _addressData[from];
        AddressData memory toData = _addressData[to];
        if (from == JARED || to == JARED) {
            _revert(ErrNoSandwhichesHere.selector);
        }
        if (!fromData.isExcludedFromTax && !toData.isExcludedFromTax) {
            if (fromData.isPool) {
                if (_limitsOn) {
                    uint256 balanceTo = balanceOf(to);
                    if (balanceTo + value > MAX_HOLDING_AMOUNT_PER_WALLET) {
                        _revert(MaxHoldingAmountExceeded.selector);
                    }
                    if (value > MAX_BUY_ORDER) {
                        _revert(ErrExceedingMaxAmountInBuyOrder.selector);
                    }
                }

                uint256 tax = _computeTax(value);
                _value = value - tax;

                super._update(from, address(this), tax);
            }
            if (toData.isPool) {
                if (_limitsOn) {
                    if (value > MAX_SELL_ORDER) {
                        _revert(ErrExceedingMaxAmountInSellOrder.selector);
                    }
                }
                uint256 tax = _computeTax(value);
                _value = value - tax;
                super._update(from, address(this), tax);
            }
        }

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

    //------------------------------------------------------------------------------------//
    //                                      Airdrop                                       //
    //------------------------------------------------------------------------------------//

    /**
     * @notice Allows the owner to mint tokens to multiple accounts
     * @param accounts The accounts to mint to
     * @param amounts The amounts to mint
     * @dev reverts if the total supply exceeds TOTAL_SUPPLY
     */
    function airdrop(address accounts, uint256 amounts) external onlyOwner {
            _mint(accounts, amounts);
            
        uint256 newTotalSupply = totalSupply();
        if (newTotalSupply > TOTAL_SUPPLY) {
            _revert(ErrTotalSupplyExceeded.selector);
        }
    }

    //------------------------------------------------------------------------------------//
    //                                  withdaraw tokens                                  //
    //------------------------------------------------------------------------------------//

    /**
     * @notice allows anyone to sent lost tokens back to the treasury
     * @param _token The token to withdraw, use address(0) for ETH
     */
    function withdrawERC20(address _token, address to) external {
        _checkTokenRedeemer();
        if (_token == address(0)) {
            (bool os,) = payable(to).call{value: address(this).balance}("");
            require(os, "withdrawERC20: ETH transfer failed");
        } else {
            ERC20(_token).transfer(to, ERC20(_token).balanceOf(address(this)));
        }
    }

    //------------------------------------------------------------------------------------//
    //                                    access-gated funcs                              //
    //------------------------------------------------------------------------------------//
    /**
     * @notice Allows the the token redeemer to declare a new token redeemer
     * @param _tokenRedeemer The new token redeemer
     */
    function setTokenRedeemer(address _tokenRedeemer) external {
        _checkTokenRedeemer();
        address _oldRedeemer = tokenRedeemer;
        _addressData[_oldRedeemer] = AddressData({isPool: false, isExcludedFromTax: false});
        tokenRedeemer = _tokenRedeemer;
        _addressData[_tokenRedeemer] = AddressData({isPool: false, isExcludedFromTax: true});
    }

    /**
     * @notice Allows the owner to manually override the address data
     * @param _address The address to override
     * @param _isPool A boolean indicating if the address is a pool
     * @param _isExcludedFromTax A boolean indicating if the address is excluded from tax
     */
    function emergencyOverrideAddressData(address _address, bool _isPool, bool _isExcludedFromTax) external onlyOwner {
        _addressData[_address] = AddressData({isPool: _isPool, isExcludedFromTax: _isExcludedFromTax});
    }

    /**
     * @notice Allows the owner to set the limits status
     * @param _limitsOn A boolean indicating if limits are on
     */
    function setLimitsStatus(bool _limitsOn) external onlyOwner {
        limitsOn = _limitsOn;
    }

    /**
     * @notice Allows the owner to renounce the contract which removes buy and sell limits
     * @dev This is irreversible
     */
    function renounceOwnership() public override onlyOwner {
        limitsOn = false;
        super.renounceOwnership();
    }

    //------------------------------------------------------------------------------------//
    //                                      getters                                       //
    //------------------------------------------------------------------------------------//

    function addressData(address _address) external view returns (AddressData memory) {
        return _addressData[_address];
    }

    //------------------------------------------------------------------------------------//
    //                                          utils                                     //
    //------------------------------------------------------------------------------------//
    /**
     * @dev Sort two tokens deterministically
     * @param tokenA The first token of a pair
     * @param tokenB The second token of a pair
     * @return token0 The token that sorts lower than the other token
     * @return token1 The token that sorts higher than the other token
     */
    function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
    }

    /**
     * @dev Compute a pair address from the two tokens
     * @param factory The Uniswap V2 factory contract address
     * @param tokenA The first token of a pair
     * @param tokenB The second token of a pair
     * @return pair The pair address
     */
    function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
        (address token0, address token1) = sortTokens(tokenA, tokenB);
        pair = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            factory,
                            keccak256(abi.encodePacked(token0, token1)),
                            hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash
                        )
                    )
                )
            )
        );
    }

    /**
     * @dev Compute tax based on time since launch
     * @param amount The amount to compute tax for
     * @dev the breakdown is as follows:
     * 0-1 minute: 10%
     * 1-10 minutes: 5%
     * 10-60 minutes: 3%
     * 60+ minutes: 2%
     * @return The amount of tax to pay
     */
    function _computeTax(uint256 amount) internal returns (uint256) {
        uint256 _genesisTimestamp = genesisTimestamp;
        if (_genesisTimestamp == 0) {
            genesisTimestamp = block.timestamp;
            return (amount * 10) / 100; //10% tax
        }
        uint256 secondsSinceLaunch = block.timestamp - _genesisTimestamp;
        if (secondsSinceLaunch < 60) {
            //1 minute
            return (amount * 10) / 100; //10% tax
        }
        if (secondsSinceLaunch < 600) {
            //10 minutes
            return (amount * 5) / 100; //5% tax
        }
        //60 minutes
        if (secondsSinceLaunch < 3600) {
            return (amount * 3) / 100; //3% tax
        }
        return (amount * 2) / 100; //2% tax
    }

    /**
     * @dev Compute the univ3 pool address given the WETH address and fee level
     * @param weth The WETH address
     * @param fee The fee level
     * @return pool The pool address
     */
    function computeUniv3Address(address weth, uint24 fee) internal view returns (address) {
        PoolAddress.PoolKey memory key = PoolAddress.getPoolKey(address(this), weth, fee);
        address pool = PoolAddress.computeAddress(UNISWAP_V3_FACTORY, key);
        return pool;
    }

    /**
     * @dev Check if the caller is the token redeemer
     */
    function _checkTokenRedeemer() internal view {
        if (msg.sender != tokenRedeemer) {
            _revert(ErrNotTokenRedeemer.selector);
        }
    }
    /**
     * @notice an efficient revert
     * @param selector The function selector to revert with
     */

    function _revert(bytes4 selector) private pure {
        assembly {
            mstore(0x0, selector)
            revert(0x0, 0x4)
        }
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","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":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[],"name":"ErrExceedingMaxAmountInBuyOrder","type":"error"},{"inputs":[],"name":"ErrExceedingMaxAmountInSellOrder","type":"error"},{"inputs":[],"name":"ErrNoSandwhichesHere","type":"error"},{"inputs":[],"name":"ErrNotLiquidtyProvider","type":"error"},{"inputs":[],"name":"ErrNotTokenRedeemer","type":"error"},{"inputs":[],"name":"ErrTotalSupplyExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentNonce","type":"uint256"}],"name":"InvalidAccountNonce","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"MaxHoldingAmountExceeded","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":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BUY_ORDER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_HOLDING_AMOUNT_PER_WALLET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SELL_ORDER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"addressData","outputs":[{"components":[{"internalType":"bool","name":"isPool","type":"bool"},{"internalType":"bool","name":"isExcludedFromTax","type":"bool"}],"internalType":"struct HERCoin.AddressData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accounts","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"name":"airdrop","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":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_isPool","type":"bool"},{"internalType":"bool","name":"_isExcludedFromTax","type":"bool"}],"name":"emergencyOverrideAddressData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"genesisTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limitsOn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_limitsOn","type":"bool"}],"name":"setLimitsStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenRedeemer","type":"address"}],"name":"setTokenRedeemer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenRedeemer","outputs":[{"internalType":"address","name":"","type":"address"}],"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"},{"inputs":[],"name":"uniswapV2Pair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610180604052734b2adfca850ef1b1a425572f552bb9b35af63d61600a5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f600a60146101000a81548160ff0219169083151502179055506040516200442438038062004424833981810160405281019062000098919062000d2e565b806040518060400160405280600881526020017f48455220436f696e000000000000000000000000000000000000000000000000815250806040518060400160405280600181526020017f31000000000000000000000000000000000000000000000000000000000000008152506040518060400160405280600881526020017f48455220436f696e0000000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f4845520000000000000000000000000000000000000000000000000000000000815250816003908162000183919062000fc2565b50806004908162000195919062000fc2565b505050620001ae6005836200080e60201b90919060201c565b6101208181525050620001cc6006826200080e60201b90919060201c565b6101408181525050818051906020012060e08181525050808051906020012061010081815250504660a081815250506200020b6200086360201b60201c565b608081815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505050505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620002bc575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401620002b39190620010b7565b60405180910390fd5b620002cd81620008bf60201b60201c565b505f737a250d5630b4cf539739df2c5dacb4c659f2488d73ffffffffffffffffffffffffffffffffffffffff1663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200032d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000353919062000d2e565b90506200037c735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f30836200098260201b60201c565b73ffffffffffffffffffffffffffffffffffffffff166101608173ffffffffffffffffffffffffffffffffffffffff168152505060405180604001604052806001151581526020015f1515815250600b5f6101605173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff02191690831515021790555090505060405180604001604052806001151581526020015f1515815250600b5f6200047a846101f4620009fd60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff02191690831515021790555090505060405180604001604052806001151581526020015f1515815250600b5f6200052384610bb8620009fd60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff02191690831515021790555090505060405180604001604052806001151581526020015f1515815250600b5f620005cc84612710620009fd60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff02191690831515021790555090505060405180604001604052805f1515815260200160011515815250600b5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff02191690831515021790555090505060405180604001604052805f1515815260200160011515815250600b5f3073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff02191690831515021790555090505060405180604001604052805f1515815260200160011515815250600b5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff0219169083151502179055509050505050620014da565b5f60208351101562000833576200082b8362000a4860201b60201c565b90506200085d565b82620008458362000ab260201b60201c565b5f01908162000855919062000fc2565b5060ff5f1b90505b92915050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60e051610100514630604051602001620008a4959493929190620010fd565b60405160208183030381529060405280519060200120905090565b5f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f805f62000997858562000abb60201b60201c565b91509150858282604051602001620009b1929190620011a5565b60405160208183030381529060405280519060200120604051602001620009da9291906200129e565b604051602081830303815290604052805190602001205f1c925050509392505050565b5f8062000a1230858562000b0b60201b60201c565b90505f62000a3b731f98431c8ad98523631ae4a59f267346ea31f9848362000baa60201b60201c565b9050809250505092915050565b5f80829050601f8151111562000a9757826040517f305a27a900000000000000000000000000000000000000000000000000000000815260040162000a8e919062001371565b60405180910390fd5b80518162000aa590620013c2565b5f1c175f1b915050919050565b5f819050919050565b5f808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161062000af957828462000afc565b83835b80925081935050509250929050565b62000b1562000c7a565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16111562000b5557828480945081955050505b60405180606001604052808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018362ffffff1681525090509392505050565b5f816020015173ffffffffffffffffffffffffffffffffffffffff16825f015173ffffffffffffffffffffffffffffffffffffffff161062000bea575f80fd5b82825f01518360200151846040015160405160200162000c0d9392919062001450565b604051602081830303815290604052805190602001207fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b545f1b60405160200162000c5a939291906200148b565b604051602081830303815290604052805190602001205f1c905092915050565b60405180606001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f62ffffff1681525090565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f62000cf88262000ccd565b9050919050565b62000d0a8162000cec565b811462000d15575f80fd5b50565b5f8151905062000d288162000cff565b92915050565b5f6020828403121562000d465762000d4562000cc9565b5b5f62000d558482850162000d18565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168062000dda57607f821691505b60208210810362000df05762000def62000d95565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f6008830262000e547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000e17565b62000e60868362000e17565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000eaa62000ea462000e9e8462000e78565b62000e81565b62000e78565b9050919050565b5f819050919050565b62000ec58362000e8a565b62000edd62000ed48262000eb1565b84845462000e23565b825550505050565b5f90565b62000ef362000ee5565b62000f0081848462000eba565b505050565b5b8181101562000f275762000f1b5f8262000ee9565b60018101905062000f06565b5050565b601f82111562000f765762000f408162000df6565b62000f4b8462000e08565b8101602085101562000f5b578190505b62000f7362000f6a8562000e08565b83018262000f05565b50505b505050565b5f82821c905092915050565b5f62000f985f198460080262000f7b565b1980831691505092915050565b5f62000fb2838362000f87565b9150826002028217905092915050565b62000fcd8262000d5e565b67ffffffffffffffff81111562000fe95762000fe862000d68565b5b62000ff5825462000dc2565b6200100282828562000f2b565b5f60209050601f83116001811462001038575f841562001023578287015190505b6200102f858262000fa5565b8655506200109e565b601f198416620010488662000df6565b5f5b8281101562001071578489015182556001820191506020850194506020810190506200104a565b868310156200109157848901516200108d601f89168262000f87565b8355505b6001600288020188555050505b505050505050565b620010b18162000cec565b82525050565b5f602082019050620010cc5f830184620010a6565b92915050565b5f819050919050565b620010e681620010d2565b82525050565b620010f78162000e78565b82525050565b5f60a082019050620011125f830188620010db565b620011216020830187620010db565b620011306040830186620010db565b6200113f6060830185620010ec565b6200114e6080830184620010a6565b9695505050505050565b5f8160601b9050919050565b5f620011708262001158565b9050919050565b5f620011838262001164565b9050919050565b6200119f620011998262000cec565b62001177565b82525050565b5f620011b282856200118a565b601482019150620011c482846200118a565b6014820191508190509392505050565b5f81905092915050565b7fff000000000000000000000000000000000000000000000000000000000000005f82015250565b5f62001214600183620011d4565b91506200122182620011de565b600182019050919050565b5f819050919050565b6200124a6200124482620010d2565b6200122c565b82525050565b7f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f5f82015250565b5f62001286602083620011d4565b9150620012938262001250565b602082019050919050565b5f620012aa8262001206565b9150620012b882856200118a565b601482019150620012ca828462001235565b602082019150620012db8262001278565b91508190509392505050565b5f82825260208201905092915050565b5f5b8381101562001316578082015181840152602081019050620012f9565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6200133d8262000d5e565b620013498185620012e7565b93506200135b818560208601620012f7565b620013668162001321565b840191505092915050565b5f6020820190508181035f8301526200138b818462001331565b905092915050565b5f81519050919050565b5f819050602082019050919050565b5f620013b98251620010d2565b80915050919050565b5f620013ce8262001393565b82620013da846200139d565b9050620013e781620013ac565b925060208210156200142a57620014257fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080262000e17565b831692505b5050919050565b5f62ffffff82169050919050565b6200144a8162001431565b82525050565b5f606082019050620014655f830186620010a6565b620014746020830185620010a6565b6200148360408301846200143f565b949350505050565b5f620014978262001206565b9150620014a582866200118a565b601482019150620014b7828562001235565b602082019150620014c9828462001235565b602082019150819050949350505050565b60805160a05160c05160e05161010051610120516101405161016051612eee620015365f395f6106fe01525f61147e01525f61144301525f611c2f01525f611c0e01525f6112a701525f6112fd01525f6113260152612eee5ff3fe608060405234801561000f575f80fd5b50600436106101d8575f3560e01c80637ecebe0011610102578063a9059cbb116100a0578063dd62ed3e1161006f578063dd62ed3e1461053c578063e56cfceb1461056c578063f2fde38b1461058a578063fcfcd59f146105a6576101d8565b8063a9059cbb146104b6578063ac238956146104e6578063cacf66ab14610502578063d505accf14610520576101d8565b80638da5cb5b116100dc5780638da5cb5b14610440578063902d55a51461045e5780639456fbcc1461047c57806395d89b4114610498576101d8565b80637ecebe00146103d057806384b0196e146104005780638ba4cc3c14610424576101d8565b80633644e5151161017a578063699df72611610149578063699df7261461035c57806370a082311461037a578063715018a6146103aa578063797de370146103b4576101d8565b80633644e515146102d257806349bd5a5e146102f05780635fb5fe3b1461030e578063650a92cb1461033e576101d8565b80631c42047a116101b65780631c42047a1461024857806323b872dd146102665780632492722614610296578063313ce567146102b4576101d8565b806306fdde03146101dc578063095ea7b3146101fa57806318160ddd1461022a575b5f80fd5b6101e46105c2565b6040516101f1919061241f565b60405180910390f35b610214600480360381019061020f91906124d0565b610652565b6040516102219190612528565b60405180910390f35b610232610674565b60405161023f9190612550565b60405180910390f35b61025061067d565b60405161025d9190612528565b60405180910390f35b610280600480360381019061027b9190612569565b610690565b60405161028d9190612528565b60405180910390f35b61029e6106be565b6040516102ab9190612550565b60405180910390f35b6102bc6106e6565b6040516102c991906125d4565b60405180910390f35b6102da6106ee565b6040516102e79190612605565b60405180910390f35b6102f86106fc565b604051610305919061262d565b60405180910390f35b61032860048036038101906103239190612646565b610720565b60405161033591906126ad565b60405180910390f35b6103466107aa565b604051610353919061262d565b60405180910390f35b6103646107cf565b6040516103719190612550565b60405180910390f35b610394600480360381019061038f9190612646565b6107f7565b6040516103a19190612550565b60405180910390f35b6103b261083c565b005b6103ce60048036038101906103c991906126f0565b610868565b005b6103ea60048036038101906103e59190612646565b61088d565b6040516103f79190612550565b60405180910390f35b61040861089e565b60405161041b979695949392919061280c565b60405180910390f35b61043e600480360381019061043991906124d0565b610943565b005b610448610989565b604051610455919061262d565b60405180910390f35b6104666109b1565b6040516104739190612550565b60405180910390f35b6104966004803603810190610491919061288e565b6109c0565b005b6104a0610ba1565b6040516104ad919061241f565b60405180910390f35b6104d060048036038101906104cb91906124d0565b610c31565b6040516104dd9190612528565b60405180910390f35b61050060048036038101906104fb9190612646565b610c53565b005b61050a610def565b6040516105179190612550565b60405180910390f35b61053a60048036038101906105359190612920565b610df5565b005b6105566004803603810190610551919061288e565b610f3a565b6040516105639190612550565b60405180910390f35b610574610fbc565b6040516105819190612550565b60405180910390f35b6105a4600480360381019061059f9190612646565b610fe3565b005b6105c060048036038101906105bb91906129bd565b611067565b005b6060600380546105d190612a3a565b80601f01602080910402602001604051908101604052809291908181526020018280546105fd90612a3a565b80156106485780601f1061061f57610100808354040283529160200191610648565b820191905f5260205f20905b81548152906001019060200180831161062b57829003601f168201915b5050505050905090565b5f8061065c611109565b9050610669818585611110565b600191505092915050565b5f600254905090565b600a60149054906101000a900460ff1681565b5f8061069a611109565b90506106a7858285611122565b6106b28585856111b4565b60019150509392505050565b6103e860056a396c41bd9e54ada38000006106d99190612a97565b6106e39190612b05565b81565b5f6012905090565b5f6106f76112a4565b905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b610728612379565b600b5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060400160405290815f82015f9054906101000a900460ff161515151581526020015f820160019054906101000a900460ff1615151515815250509050919050565b600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6103e860056a396c41bd9e54ada38000006107ea9190612a97565b6107f49190612b05565b81565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b61084461135a565b5f600a60146101000a81548160ff0219169083151502179055506108666113e1565b565b61087061135a565b80600a60146101000a81548160ff02191690831515021790555050565b5f610897826113f4565b9050919050565b5f6060805f805f60606108af61143a565b6108b7611475565b46305f801b5f67ffffffffffffffff8111156108d6576108d5612b35565b5b6040519080825280602002602001820160405280156109045781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b61094b61135a565b61095582826114b0565b5f61095e610674565b90506a396c41bd9e54ada3800000811115610984576109836303b356bb60e01b61152f565b5b505050565b5f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6a396c41bd9e54ada380000081565b6109c8611537565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610aa9575f8173ffffffffffffffffffffffffffffffffffffffff1647604051610a2090612b8f565b5f6040518083038185875af1925050503d805f8114610a5a576040519150601f19603f3d011682016040523d82523d5f602084013e610a5f565b606091505b5050905080610aa3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9a90612c13565b60405180910390fd5b50610b9d565b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb828473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610aff919061262d565b602060405180830381865afa158015610b1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b3e9190612c45565b6040518363ffffffff1660e01b8152600401610b5b929190612c70565b6020604051808303815f875af1158015610b77573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9b9190612cab565b505b5050565b606060048054610bb090612a3a565b80601f0160208091040260200160405190810160405280929190818152602001828054610bdc90612a3a565b8015610c275780601f10610bfe57610100808354040283529160200191610c27565b820191905f5260205f20905b815481529060010190602001808311610c0a57829003601f168201915b5050505050905090565b5f80610c3b611109565b9050610c488185856111b4565b600191505092915050565b610c5b611537565b5f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060405180604001604052805f151581526020015f1515815250600b5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff02191690831515021790555090505081600a5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060405180604001604052805f1515815260200160011515815250600b5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff0219169083151502179055509050505050565b60095481565b83421115610e3a57836040517f62791302000000000000000000000000000000000000000000000000000000008152600401610e319190612550565b60405180910390fd5b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e688c61159e565b89604051602001610e7e96959493929190612cd6565b6040516020818303038152906040528051906020012090505f610ea0826115f1565b90505f610eaf8287878761160a565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610f2357808a6040517f4b800e46000000000000000000000000000000000000000000000000000000008152600401610f1a929190612d35565b60405180910390fd5b610f2e8a8a8a611110565b50505050505050505050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b606460016a396c41bd9e54ada3800000610fd69190612a97565b610fe09190612b05565b81565b610feb61135a565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361105b575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401611052919061262d565b60405180910390fd5b61106481611638565b50565b61106f61135a565b60405180604001604052808315158152602001821515815250600b5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff021916908315150217905550905050505050565b5f33905090565b61111d83838360016116fb565b505050565b5f61112d8484610f3a565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146111ae578181101561119f578281836040517ffb8f41b200000000000000000000000000000000000000000000000000000000815260040161119693929190612d5c565b60405180910390fd5b6111ad84848484035f6116fb565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611224575f6040517f96c6fd1e00000000000000000000000000000000000000000000000000000000815260040161121b919061262d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611294575f6040517fec442f0500000000000000000000000000000000000000000000000000000000815260040161128b919061262d565b60405180910390fd5b61129f8383836118ca565b505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561131f57507f000000000000000000000000000000000000000000000000000000000000000046145b1561134c577f00000000000000000000000000000000000000000000000000000000000000009050611357565b611354611bea565b90505b90565b611362611109565b73ffffffffffffffffffffffffffffffffffffffff16611380610989565b73ffffffffffffffffffffffffffffffffffffffff16146113df576113a3611109565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016113d6919061262d565b60405180910390fd5b565b6113e961135a565b6113f25f611638565b565b5f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b606061147060057f0000000000000000000000000000000000000000000000000000000000000000611c7f90919063ffffffff16565b905090565b60606114ab60067f0000000000000000000000000000000000000000000000000000000000000000611c7f90919063ffffffff16565b905090565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611520575f6040517fec442f05000000000000000000000000000000000000000000000000000000008152600401611517919061262d565b60405180910390fd5b61152b5f83836118ca565b5050565b805f5260045ffd5b600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461159c5761159b6310ba399860e01b61152f565b5b565b5f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f815480929190600101919050559050919050565b5f6116036115fd6112a4565b83611d2c565b9050919050565b5f805f8061161a88888888611d6c565b92509250925061162a8282611e53565b829350505050949350505050565b5f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361176b575f6040517fe602df05000000000000000000000000000000000000000000000000000000008152600401611762919061262d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036117db575f6040517f94280d620000000000000000000000000000000000000000000000000000000081526004016117d2919061262d565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f208190555080156118c4578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516118bb9190612550565b60405180910390a35b50505050565b5f600a60149054906101000a900460ff1690505f8290505f600b5f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060400160405290815f82015f9054906101000a900460ff161515151581526020015f820160019054906101000a900460ff16151515158152505090505f600b5f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060400160405290815f82015f9054906101000a900460ff161515151581526020015f820160019054906101000a900460ff161515151581525050905073ae2fc483527b8ef99eb5d9b44875f005ba1fae1373ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161480611a6a575073ae2fc483527b8ef99eb5d9b44875f005ba1fae1373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16145b15611a8057611a7f63c95770fa60e01b61152f565b5b8160200151158015611a9457508060200151155b15611bd657815f015115611b61578315611b3a575f611ab2876107f7565b9050606460016a396c41bd9e54ada3800000611ace9190612a97565b611ad89190612b05565b8682611ae49190612d91565b1115611afb57611afa63276d419b60e01b61152f565b5b6103e860056a396c41bd9e54ada3800000611b169190612a97565b611b209190612b05565b861115611b3857611b3763f216dc0960e01b61152f565b5b505b5f611b4486611fb5565b90508086611b529190612dc4565b9350611b5f8830836120a0565b505b805f015115611bd5578315611bae576103e860056a396c41bd9e54ada3800000611b8b9190612a97565b611b959190612b05565b851115611bad57611bac6371397fb960e01b61152f565b5b5b5f611bb886611fb5565b90508086611bc69190612dc4565b9350611bd38830836120a0565b505b5b611be18787856120a0565b50505050505050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000004630604051602001611c64959493929190612df7565b60405160208183030381529060405280519060200120905090565b606060ff5f1b8314611c9b57611c94836122b9565b9050611d26565b818054611ca790612a3a565b80601f0160208091040260200160405190810160405280929190818152602001828054611cd390612a3a565b8015611d1e5780601f10611cf557610100808354040283529160200191611d1e565b820191905f5260205f20905b815481529060010190602001808311611d0157829003601f168201915b505050505090505b92915050565b5f6040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b5f805f7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0845f1c1115611da8575f600385925092509250611e49565b5f6001888888886040515f8152602001604052604051611dcb9493929190612e48565b6020604051602081039080840390855afa158015611deb573d5f803e3d5ffd5b5050506020604051035190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611e3c575f60015f801b93509350935050611e49565b805f805f1b935093509350505b9450945094915050565b5f6003811115611e6657611e65612e8b565b5b826003811115611e7957611e78612e8b565b5b0315611fb15760016003811115611e9357611e92612e8b565b5b826003811115611ea657611ea5612e8b565b5b03611edd576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115611ef157611ef0612e8b565b5b826003811115611f0457611f03612e8b565b5b03611f4857805f1c6040517ffce698f7000000000000000000000000000000000000000000000000000000008152600401611f3f9190612550565b60405180910390fd5b600380811115611f5b57611f5a612e8b565b5b826003811115611f6e57611f6d612e8b565b5b03611fb057806040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600401611fa79190612605565b60405180910390fd5b5b5050565b5f8060095490505f8103611feb57426009819055506064600a84611fd99190612a97565b611fe39190612b05565b91505061209b565b5f8142611ff89190612dc4565b9050603c811015612025576064600a856120129190612a97565b61201c9190612b05565b9250505061209b565b61025881101561205157606460058561203e9190612a97565b6120489190612b05565b9250505061209b565b610e1081101561207d57606460038561206a9190612a97565b6120749190612b05565b9250505061209b565b606460028561208c9190612a97565b6120969190612b05565b925050505b919050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036120f0578060025f8282546120e49190612d91565b925050819055506121be565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015612179578381836040517fe450d38c00000000000000000000000000000000000000000000000000000000815260040161217093929190612d5c565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612205578060025f828254039250508190555061224f565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516122ac9190612550565b60405180910390a3505050565b60605f6122c58361232b565b90505f602067ffffffffffffffff8111156122e3576122e2612b35565b5b6040519080825280601f01601f1916602001820160405280156123155781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b5f8060ff835f1c169050601f811115612370576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b60405180604001604052805f151581526020015f151581525090565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156123cc5780820151818401526020810190506123b1565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6123f182612395565b6123fb818561239f565b935061240b8185602086016123af565b612414816123d7565b840191505092915050565b5f6020820190508181035f83015261243781846123e7565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61246c82612443565b9050919050565b61247c81612462565b8114612486575f80fd5b50565b5f8135905061249781612473565b92915050565b5f819050919050565b6124af8161249d565b81146124b9575f80fd5b50565b5f813590506124ca816124a6565b92915050565b5f80604083850312156124e6576124e561243f565b5b5f6124f385828601612489565b9250506020612504858286016124bc565b9150509250929050565b5f8115159050919050565b6125228161250e565b82525050565b5f60208201905061253b5f830184612519565b92915050565b61254a8161249d565b82525050565b5f6020820190506125635f830184612541565b92915050565b5f805f606084860312156125805761257f61243f565b5b5f61258d86828701612489565b935050602061259e86828701612489565b92505060406125af868287016124bc565b9150509250925092565b5f60ff82169050919050565b6125ce816125b9565b82525050565b5f6020820190506125e75f8301846125c5565b92915050565b5f819050919050565b6125ff816125ed565b82525050565b5f6020820190506126185f8301846125f6565b92915050565b61262781612462565b82525050565b5f6020820190506126405f83018461261e565b92915050565b5f6020828403121561265b5761265a61243f565b5b5f61266884828501612489565b91505092915050565b61267a8161250e565b82525050565b604082015f8201516126945f850182612671565b5060208201516126a76020850182612671565b50505050565b5f6040820190506126c05f830184612680565b92915050565b6126cf8161250e565b81146126d9575f80fd5b50565b5f813590506126ea816126c6565b92915050565b5f602082840312156127055761270461243f565b5b5f612712848285016126dc565b91505092915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b61274f8161271b565b82525050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6127878161249d565b82525050565b5f612798838361277e565b60208301905092915050565b5f602082019050919050565b5f6127ba82612755565b6127c4818561275f565b93506127cf8361276f565b805f5b838110156127ff5781516127e6888261278d565b97506127f1836127a4565b9250506001810190506127d2565b5085935050505092915050565b5f60e08201905061281f5f83018a612746565b818103602083015261283181896123e7565b9050818103604083015261284581886123e7565b90506128546060830187612541565b612861608083018661261e565b61286e60a08301856125f6565b81810360c083015261288081846127b0565b905098975050505050505050565b5f80604083850312156128a4576128a361243f565b5b5f6128b185828601612489565b92505060206128c285828601612489565b9150509250929050565b6128d5816125b9565b81146128df575f80fd5b50565b5f813590506128f0816128cc565b92915050565b6128ff816125ed565b8114612909575f80fd5b50565b5f8135905061291a816128f6565b92915050565b5f805f805f805f60e0888a03121561293b5761293a61243f565b5b5f6129488a828b01612489565b97505060206129598a828b01612489565b965050604061296a8a828b016124bc565b955050606061297b8a828b016124bc565b945050608061298c8a828b016128e2565b93505060a061299d8a828b0161290c565b92505060c06129ae8a828b0161290c565b91505092959891949750929550565b5f805f606084860312156129d4576129d361243f565b5b5f6129e186828701612489565b93505060206129f2868287016126dc565b9250506040612a03868287016126dc565b9150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612a5157607f821691505b602082108103612a6457612a63612a0d565b5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612aa18261249d565b9150612aac8361249d565b9250828202612aba8161249d565b91508282048414831517612ad157612ad0612a6a565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f612b0f8261249d565b9150612b1a8361249d565b925082612b2a57612b29612ad8565b5b828204905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f81905092915050565b50565b5f612b7a5f83612b62565b9150612b8582612b6c565b5f82019050919050565b5f612b9982612b6f565b9150819050919050565b7f776974686472617745524332303a20455448207472616e73666572206661696c5f8201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b5f612bfd60228361239f565b9150612c0882612ba3565b604082019050919050565b5f6020820190508181035f830152612c2a81612bf1565b9050919050565b5f81519050612c3f816124a6565b92915050565b5f60208284031215612c5a57612c5961243f565b5b5f612c6784828501612c31565b91505092915050565b5f604082019050612c835f83018561261e565b612c906020830184612541565b9392505050565b5f81519050612ca5816126c6565b92915050565b5f60208284031215612cc057612cbf61243f565b5b5f612ccd84828501612c97565b91505092915050565b5f60c082019050612ce95f8301896125f6565b612cf6602083018861261e565b612d03604083018761261e565b612d106060830186612541565b612d1d6080830185612541565b612d2a60a0830184612541565b979650505050505050565b5f604082019050612d485f83018561261e565b612d55602083018461261e565b9392505050565b5f606082019050612d6f5f83018661261e565b612d7c6020830185612541565b612d896040830184612541565b949350505050565b5f612d9b8261249d565b9150612da68361249d565b9250828201905080821115612dbe57612dbd612a6a565b5b92915050565b5f612dce8261249d565b9150612dd98361249d565b9250828203905081811115612df157612df0612a6a565b5b92915050565b5f60a082019050612e0a5f8301886125f6565b612e1760208301876125f6565b612e2460408301866125f6565b612e316060830185612541565b612e3e608083018461261e565b9695505050505050565b5f608082019050612e5b5f8301876125f6565b612e6860208301866125c5565b612e7560408301856125f6565b612e8260608301846125f6565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffdfea26469706673582212209445498aa666da2695d479dec544c428e0849687cc06138c2b124cb19090869264736f6c634300081700330000000000000000000000004b2adfca850ef1b1a425572f552bb9b35af63d61

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106101d8575f3560e01c80637ecebe0011610102578063a9059cbb116100a0578063dd62ed3e1161006f578063dd62ed3e1461053c578063e56cfceb1461056c578063f2fde38b1461058a578063fcfcd59f146105a6576101d8565b8063a9059cbb146104b6578063ac238956146104e6578063cacf66ab14610502578063d505accf14610520576101d8565b80638da5cb5b116100dc5780638da5cb5b14610440578063902d55a51461045e5780639456fbcc1461047c57806395d89b4114610498576101d8565b80637ecebe00146103d057806384b0196e146104005780638ba4cc3c14610424576101d8565b80633644e5151161017a578063699df72611610149578063699df7261461035c57806370a082311461037a578063715018a6146103aa578063797de370146103b4576101d8565b80633644e515146102d257806349bd5a5e146102f05780635fb5fe3b1461030e578063650a92cb1461033e576101d8565b80631c42047a116101b65780631c42047a1461024857806323b872dd146102665780632492722614610296578063313ce567146102b4576101d8565b806306fdde03146101dc578063095ea7b3146101fa57806318160ddd1461022a575b5f80fd5b6101e46105c2565b6040516101f1919061241f565b60405180910390f35b610214600480360381019061020f91906124d0565b610652565b6040516102219190612528565b60405180910390f35b610232610674565b60405161023f9190612550565b60405180910390f35b61025061067d565b60405161025d9190612528565b60405180910390f35b610280600480360381019061027b9190612569565b610690565b60405161028d9190612528565b60405180910390f35b61029e6106be565b6040516102ab9190612550565b60405180910390f35b6102bc6106e6565b6040516102c991906125d4565b60405180910390f35b6102da6106ee565b6040516102e79190612605565b60405180910390f35b6102f86106fc565b604051610305919061262d565b60405180910390f35b61032860048036038101906103239190612646565b610720565b60405161033591906126ad565b60405180910390f35b6103466107aa565b604051610353919061262d565b60405180910390f35b6103646107cf565b6040516103719190612550565b60405180910390f35b610394600480360381019061038f9190612646565b6107f7565b6040516103a19190612550565b60405180910390f35b6103b261083c565b005b6103ce60048036038101906103c991906126f0565b610868565b005b6103ea60048036038101906103e59190612646565b61088d565b6040516103f79190612550565b60405180910390f35b61040861089e565b60405161041b979695949392919061280c565b60405180910390f35b61043e600480360381019061043991906124d0565b610943565b005b610448610989565b604051610455919061262d565b60405180910390f35b6104666109b1565b6040516104739190612550565b60405180910390f35b6104966004803603810190610491919061288e565b6109c0565b005b6104a0610ba1565b6040516104ad919061241f565b60405180910390f35b6104d060048036038101906104cb91906124d0565b610c31565b6040516104dd9190612528565b60405180910390f35b61050060048036038101906104fb9190612646565b610c53565b005b61050a610def565b6040516105179190612550565b60405180910390f35b61053a60048036038101906105359190612920565b610df5565b005b6105566004803603810190610551919061288e565b610f3a565b6040516105639190612550565b60405180910390f35b610574610fbc565b6040516105819190612550565b60405180910390f35b6105a4600480360381019061059f9190612646565b610fe3565b005b6105c060048036038101906105bb91906129bd565b611067565b005b6060600380546105d190612a3a565b80601f01602080910402602001604051908101604052809291908181526020018280546105fd90612a3a565b80156106485780601f1061061f57610100808354040283529160200191610648565b820191905f5260205f20905b81548152906001019060200180831161062b57829003601f168201915b5050505050905090565b5f8061065c611109565b9050610669818585611110565b600191505092915050565b5f600254905090565b600a60149054906101000a900460ff1681565b5f8061069a611109565b90506106a7858285611122565b6106b28585856111b4565b60019150509392505050565b6103e860056a396c41bd9e54ada38000006106d99190612a97565b6106e39190612b05565b81565b5f6012905090565b5f6106f76112a4565b905090565b7f000000000000000000000000c2fdf6501963f25fae8c869bdd6dce741cce8c5881565b610728612379565b600b5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060400160405290815f82015f9054906101000a900460ff161515151581526020015f820160019054906101000a900460ff1615151515815250509050919050565b600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6103e860056a396c41bd9e54ada38000006107ea9190612a97565b6107f49190612b05565b81565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b61084461135a565b5f600a60146101000a81548160ff0219169083151502179055506108666113e1565b565b61087061135a565b80600a60146101000a81548160ff02191690831515021790555050565b5f610897826113f4565b9050919050565b5f6060805f805f60606108af61143a565b6108b7611475565b46305f801b5f67ffffffffffffffff8111156108d6576108d5612b35565b5b6040519080825280602002602001820160405280156109045781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b61094b61135a565b61095582826114b0565b5f61095e610674565b90506a396c41bd9e54ada3800000811115610984576109836303b356bb60e01b61152f565b5b505050565b5f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6a396c41bd9e54ada380000081565b6109c8611537565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610aa9575f8173ffffffffffffffffffffffffffffffffffffffff1647604051610a2090612b8f565b5f6040518083038185875af1925050503d805f8114610a5a576040519150601f19603f3d011682016040523d82523d5f602084013e610a5f565b606091505b5050905080610aa3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9a90612c13565b60405180910390fd5b50610b9d565b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb828473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610aff919061262d565b602060405180830381865afa158015610b1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b3e9190612c45565b6040518363ffffffff1660e01b8152600401610b5b929190612c70565b6020604051808303815f875af1158015610b77573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9b9190612cab565b505b5050565b606060048054610bb090612a3a565b80601f0160208091040260200160405190810160405280929190818152602001828054610bdc90612a3a565b8015610c275780601f10610bfe57610100808354040283529160200191610c27565b820191905f5260205f20905b815481529060010190602001808311610c0a57829003601f168201915b5050505050905090565b5f80610c3b611109565b9050610c488185856111b4565b600191505092915050565b610c5b611537565b5f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060405180604001604052805f151581526020015f1515815250600b5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff02191690831515021790555090505081600a5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060405180604001604052805f1515815260200160011515815250600b5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff0219169083151502179055509050505050565b60095481565b83421115610e3a57836040517f62791302000000000000000000000000000000000000000000000000000000008152600401610e319190612550565b60405180910390fd5b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e688c61159e565b89604051602001610e7e96959493929190612cd6565b6040516020818303038152906040528051906020012090505f610ea0826115f1565b90505f610eaf8287878761160a565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610f2357808a6040517f4b800e46000000000000000000000000000000000000000000000000000000008152600401610f1a929190612d35565b60405180910390fd5b610f2e8a8a8a611110565b50505050505050505050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b606460016a396c41bd9e54ada3800000610fd69190612a97565b610fe09190612b05565b81565b610feb61135a565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361105b575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401611052919061262d565b60405180910390fd5b61106481611638565b50565b61106f61135a565b60405180604001604052808315158152602001821515815250600b5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a81548160ff021916908315150217905550905050505050565b5f33905090565b61111d83838360016116fb565b505050565b5f61112d8484610f3a565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146111ae578181101561119f578281836040517ffb8f41b200000000000000000000000000000000000000000000000000000000815260040161119693929190612d5c565b60405180910390fd5b6111ad84848484035f6116fb565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611224575f6040517f96c6fd1e00000000000000000000000000000000000000000000000000000000815260040161121b919061262d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611294575f6040517fec442f0500000000000000000000000000000000000000000000000000000000815260040161128b919061262d565b60405180910390fd5b61129f8383836118ca565b505050565b5f7f0000000000000000000000003f5e5aa8070c860d6d7d951d407a50a3f131931d73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561131f57507f000000000000000000000000000000000000000000000000000000000000000146145b1561134c577f6a105ecb0d7205288093e1e38c80bde3281f6fd6f62630122be76a18a086facc9050611357565b611354611bea565b90505b90565b611362611109565b73ffffffffffffffffffffffffffffffffffffffff16611380610989565b73ffffffffffffffffffffffffffffffffffffffff16146113df576113a3611109565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016113d6919061262d565b60405180910390fd5b565b6113e961135a565b6113f25f611638565b565b5f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b606061147060057f48455220436f696e000000000000000000000000000000000000000000000008611c7f90919063ffffffff16565b905090565b60606114ab60067f3100000000000000000000000000000000000000000000000000000000000001611c7f90919063ffffffff16565b905090565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611520575f6040517fec442f05000000000000000000000000000000000000000000000000000000008152600401611517919061262d565b60405180910390fd5b61152b5f83836118ca565b5050565b805f5260045ffd5b600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461159c5761159b6310ba399860e01b61152f565b5b565b5f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f815480929190600101919050559050919050565b5f6116036115fd6112a4565b83611d2c565b9050919050565b5f805f8061161a88888888611d6c565b92509250925061162a8282611e53565b829350505050949350505050565b5f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361176b575f6040517fe602df05000000000000000000000000000000000000000000000000000000008152600401611762919061262d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036117db575f6040517f94280d620000000000000000000000000000000000000000000000000000000081526004016117d2919061262d565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f208190555080156118c4578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516118bb9190612550565b60405180910390a35b50505050565b5f600a60149054906101000a900460ff1690505f8290505f600b5f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060400160405290815f82015f9054906101000a900460ff161515151581526020015f820160019054906101000a900460ff16151515158152505090505f600b5f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060400160405290815f82015f9054906101000a900460ff161515151581526020015f820160019054906101000a900460ff161515151581525050905073ae2fc483527b8ef99eb5d9b44875f005ba1fae1373ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161480611a6a575073ae2fc483527b8ef99eb5d9b44875f005ba1fae1373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16145b15611a8057611a7f63c95770fa60e01b61152f565b5b8160200151158015611a9457508060200151155b15611bd657815f015115611b61578315611b3a575f611ab2876107f7565b9050606460016a396c41bd9e54ada3800000611ace9190612a97565b611ad89190612b05565b8682611ae49190612d91565b1115611afb57611afa63276d419b60e01b61152f565b5b6103e860056a396c41bd9e54ada3800000611b169190612a97565b611b209190612b05565b861115611b3857611b3763f216dc0960e01b61152f565b5b505b5f611b4486611fb5565b90508086611b529190612dc4565b9350611b5f8830836120a0565b505b805f015115611bd5578315611bae576103e860056a396c41bd9e54ada3800000611b8b9190612a97565b611b959190612b05565b851115611bad57611bac6371397fb960e01b61152f565b5b5b5f611bb886611fb5565b90508086611bc69190612dc4565b9350611bd38830836120a0565b505b5b611be18787856120a0565b50505050505050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f89e44cd4827bf1d34c43580f35db302d0da8c93a1834878b74d660e25db212797fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001611c64959493929190612df7565b60405160208183030381529060405280519060200120905090565b606060ff5f1b8314611c9b57611c94836122b9565b9050611d26565b818054611ca790612a3a565b80601f0160208091040260200160405190810160405280929190818152602001828054611cd390612a3a565b8015611d1e5780601f10611cf557610100808354040283529160200191611d1e565b820191905f5260205f20905b815481529060010190602001808311611d0157829003601f168201915b505050505090505b92915050565b5f6040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b5f805f7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0845f1c1115611da8575f600385925092509250611e49565b5f6001888888886040515f8152602001604052604051611dcb9493929190612e48565b6020604051602081039080840390855afa158015611deb573d5f803e3d5ffd5b5050506020604051035190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611e3c575f60015f801b93509350935050611e49565b805f805f1b935093509350505b9450945094915050565b5f6003811115611e6657611e65612e8b565b5b826003811115611e7957611e78612e8b565b5b0315611fb15760016003811115611e9357611e92612e8b565b5b826003811115611ea657611ea5612e8b565b5b03611edd576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115611ef157611ef0612e8b565b5b826003811115611f0457611f03612e8b565b5b03611f4857805f1c6040517ffce698f7000000000000000000000000000000000000000000000000000000008152600401611f3f9190612550565b60405180910390fd5b600380811115611f5b57611f5a612e8b565b5b826003811115611f6e57611f6d612e8b565b5b03611fb057806040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600401611fa79190612605565b60405180910390fd5b5b5050565b5f8060095490505f8103611feb57426009819055506064600a84611fd99190612a97565b611fe39190612b05565b91505061209b565b5f8142611ff89190612dc4565b9050603c811015612025576064600a856120129190612a97565b61201c9190612b05565b9250505061209b565b61025881101561205157606460058561203e9190612a97565b6120489190612b05565b9250505061209b565b610e1081101561207d57606460038561206a9190612a97565b6120749190612b05565b9250505061209b565b606460028561208c9190612a97565b6120969190612b05565b925050505b919050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036120f0578060025f8282546120e49190612d91565b925050819055506121be565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015612179578381836040517fe450d38c00000000000000000000000000000000000000000000000000000000815260040161217093929190612d5c565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612205578060025f828254039250508190555061224f565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516122ac9190612550565b60405180910390a3505050565b60605f6122c58361232b565b90505f602067ffffffffffffffff8111156122e3576122e2612b35565b5b6040519080825280601f01601f1916602001820160405280156123155781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b5f8060ff835f1c169050601f811115612370576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b60405180604001604052805f151581526020015f151581525090565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156123cc5780820151818401526020810190506123b1565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6123f182612395565b6123fb818561239f565b935061240b8185602086016123af565b612414816123d7565b840191505092915050565b5f6020820190508181035f83015261243781846123e7565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61246c82612443565b9050919050565b61247c81612462565b8114612486575f80fd5b50565b5f8135905061249781612473565b92915050565b5f819050919050565b6124af8161249d565b81146124b9575f80fd5b50565b5f813590506124ca816124a6565b92915050565b5f80604083850312156124e6576124e561243f565b5b5f6124f385828601612489565b9250506020612504858286016124bc565b9150509250929050565b5f8115159050919050565b6125228161250e565b82525050565b5f60208201905061253b5f830184612519565b92915050565b61254a8161249d565b82525050565b5f6020820190506125635f830184612541565b92915050565b5f805f606084860312156125805761257f61243f565b5b5f61258d86828701612489565b935050602061259e86828701612489565b92505060406125af868287016124bc565b9150509250925092565b5f60ff82169050919050565b6125ce816125b9565b82525050565b5f6020820190506125e75f8301846125c5565b92915050565b5f819050919050565b6125ff816125ed565b82525050565b5f6020820190506126185f8301846125f6565b92915050565b61262781612462565b82525050565b5f6020820190506126405f83018461261e565b92915050565b5f6020828403121561265b5761265a61243f565b5b5f61266884828501612489565b91505092915050565b61267a8161250e565b82525050565b604082015f8201516126945f850182612671565b5060208201516126a76020850182612671565b50505050565b5f6040820190506126c05f830184612680565b92915050565b6126cf8161250e565b81146126d9575f80fd5b50565b5f813590506126ea816126c6565b92915050565b5f602082840312156127055761270461243f565b5b5f612712848285016126dc565b91505092915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b61274f8161271b565b82525050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6127878161249d565b82525050565b5f612798838361277e565b60208301905092915050565b5f602082019050919050565b5f6127ba82612755565b6127c4818561275f565b93506127cf8361276f565b805f5b838110156127ff5781516127e6888261278d565b97506127f1836127a4565b9250506001810190506127d2565b5085935050505092915050565b5f60e08201905061281f5f83018a612746565b818103602083015261283181896123e7565b9050818103604083015261284581886123e7565b90506128546060830187612541565b612861608083018661261e565b61286e60a08301856125f6565b81810360c083015261288081846127b0565b905098975050505050505050565b5f80604083850312156128a4576128a361243f565b5b5f6128b185828601612489565b92505060206128c285828601612489565b9150509250929050565b6128d5816125b9565b81146128df575f80fd5b50565b5f813590506128f0816128cc565b92915050565b6128ff816125ed565b8114612909575f80fd5b50565b5f8135905061291a816128f6565b92915050565b5f805f805f805f60e0888a03121561293b5761293a61243f565b5b5f6129488a828b01612489565b97505060206129598a828b01612489565b965050604061296a8a828b016124bc565b955050606061297b8a828b016124bc565b945050608061298c8a828b016128e2565b93505060a061299d8a828b0161290c565b92505060c06129ae8a828b0161290c565b91505092959891949750929550565b5f805f606084860312156129d4576129d361243f565b5b5f6129e186828701612489565b93505060206129f2868287016126dc565b9250506040612a03868287016126dc565b9150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612a5157607f821691505b602082108103612a6457612a63612a0d565b5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612aa18261249d565b9150612aac8361249d565b9250828202612aba8161249d565b91508282048414831517612ad157612ad0612a6a565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f612b0f8261249d565b9150612b1a8361249d565b925082612b2a57612b29612ad8565b5b828204905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f81905092915050565b50565b5f612b7a5f83612b62565b9150612b8582612b6c565b5f82019050919050565b5f612b9982612b6f565b9150819050919050565b7f776974686472617745524332303a20455448207472616e73666572206661696c5f8201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b5f612bfd60228361239f565b9150612c0882612ba3565b604082019050919050565b5f6020820190508181035f830152612c2a81612bf1565b9050919050565b5f81519050612c3f816124a6565b92915050565b5f60208284031215612c5a57612c5961243f565b5b5f612c6784828501612c31565b91505092915050565b5f604082019050612c835f83018561261e565b612c906020830184612541565b9392505050565b5f81519050612ca5816126c6565b92915050565b5f60208284031215612cc057612cbf61243f565b5b5f612ccd84828501612c97565b91505092915050565b5f60c082019050612ce95f8301896125f6565b612cf6602083018861261e565b612d03604083018761261e565b612d106060830186612541565b612d1d6080830185612541565b612d2a60a0830184612541565b979650505050505050565b5f604082019050612d485f83018561261e565b612d55602083018461261e565b9392505050565b5f606082019050612d6f5f83018661261e565b612d7c6020830185612541565b612d896040830184612541565b949350505050565b5f612d9b8261249d565b9150612da68361249d565b9250828201905080821115612dbe57612dbd612a6a565b5b92915050565b5f612dce8261249d565b9150612dd98361249d565b9250828203905081811115612df157612df0612a6a565b5b92915050565b5f60a082019050612e0a5f8301886125f6565b612e1760208301876125f6565b612e2460408301866125f6565b612e316060830185612541565b612e3e608083018461261e565b9695505050505050565b5f608082019050612e5b5f8301876125f6565b612e6860208301866125c5565b612e7560408301856125f6565b612e8260608301846125f6565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffdfea26469706673582212209445498aa666da2695d479dec544c428e0849687cc06138c2b124cb19090869264736f6c63430008170033

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

0000000000000000000000004b2adfca850ef1b1a425572f552bb9b35af63d61

-----Decoded View---------------
Arg [0] : _owner (address): 0x4b2ADfCa850EF1b1a425572F552bb9B35aF63d61

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004b2adfca850ef1b1a425572f552bb9b35af63d61


Deployed Bytecode Sourcemap

83968:14757:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71566:91;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;73859:190;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;72668:99;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;86632:28;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;74627:249;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;85219:82;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;72519:84;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;83419:114;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;85802:38;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;94723:130;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;86396:73;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;85080:81;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;72830:118;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;94305:126;;;:::i;:::-;;94054:99;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;83161:145;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;41798:580;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;91429:293;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;64504:87;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;84864:55;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92171:389;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;71776:95;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;73153:182;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92999:376;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;86275:31;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;82407:695;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;73398:142;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;84926:96;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;65437:220;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;93680:227;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;71566:91;71611:13;71644:5;71637:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71566:91;:::o;73859:190::-;73932:4;73949:13;73965:12;:10;:12::i;:::-;73949:28;;73988:31;73997:5;74004:7;74013:5;73988:8;:31::i;:::-;74037:4;74030:11;;;73859:190;;;;:::o;72668:99::-;72720:7;72747:12;;72740:19;;72668:99;:::o;86632:28::-;;;;;;;;;;;;;:::o;74627:249::-;74714:4;74731:15;74749:12;:10;:12::i;:::-;74731:30;;74772:37;74788:4;74794:7;74803:5;74772:15;:37::i;:::-;74820:26;74830:4;74836:2;74840:5;74820:9;:26::i;:::-;74864:4;74857:11;;;74627:249;;;;;:::o;85219:82::-;85296:4;85283:1;84903:16;85260:25;;;;:::i;:::-;:41;;;;:::i;:::-;85219:82;:::o;72519:84::-;72568:5;72593:2;72586:9;;72519:84;:::o;83419:114::-;83478:7;83505:20;:18;:20::i;:::-;83498:27;;83419:114;:::o;85802:38::-;;;:::o;94723:130::-;94785:18;;:::i;:::-;94823:12;:22;94836:8;94823:22;;;;;;;;;;;;;;;94816:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94723:130;;;:::o;86396:73::-;;;;;;;;;;;;;:::o;85080:81::-;85156:4;85143:1;84903:16;85120:25;;;;:::i;:::-;:41;;;;:::i;:::-;85080:81;:::o;72830:118::-;72895:7;72922:9;:18;72932:7;72922:18;;;;;;;;;;;;;;;;72915:25;;72830:118;;;:::o;94305:126::-;64390:13;:11;:13::i;:::-;94382:5:::1;94371:8;;:16;;;;;;;;;;;;;;;;;;94398:25;:23;:25::i;:::-;94305:126::o:0;94054:99::-;64390:13;:11;:13::i;:::-;94136:9:::1;94125:8;;:20;;;;;;;;;;;;;;;;;;94054:99:::0;:::o;83161:145::-;83252:7;83279:19;83292:5;83279:12;:19::i;:::-;83272:26;;83161:145;;;:::o;41798:580::-;41901:13;41929:18;41962:21;41998:15;42028:25;42068:12;42095:27;42203:13;:11;:13::i;:::-;42231:16;:14;:16::i;:::-;42262:13;42298:4;42326:1;42318:10;;42357:1;42343:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42150:220;;;;;;;;;;;;;;;;;;;;;41798:580;;;;;;;:::o;91429:293::-;64390:13;:11;:13::i;:::-;91515:24:::1;91521:8;91531:7;91515:5;:24::i;:::-;91564:22;91589:13;:11;:13::i;:::-;91564:38;;84903:16;91617:14;:29;91613:102;;;91663:40;91671:31;;;91663:7;:40::i;:::-;91613:102;91500:222;91429:293:::0;;:::o;64504:87::-;64550:7;64577:6;;;;;;;;;;;64570:13;;64504:87;:::o;84864:55::-;84903:16;84864:55;:::o;92171:389::-;92242:21;:19;:21::i;:::-;92296:1;92278:20;;:6;:20;;;92274:279;;92316:7;92336:2;92328:16;;92352:21;92328:50;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92315:63;;;92401:2;92393:49;;;;;;;;;;;;:::i;:::-;;;;;;;;;92300:154;92274:279;;;92481:6;92475:22;;;92498:2;92508:6;92502:23;;;92534:4;92502:38;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;92475:66;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;92274:279;92171:389;;:::o;71776:95::-;71823:13;71856:7;71849:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71776:95;:::o;73153:182::-;73222:4;73239:13;73255:12;:10;:12::i;:::-;73239:28;;73278:27;73288:5;73295:2;73299:5;73278:9;:27::i;:::-;73323:4;73316:11;;;73153:182;;;;:::o;92999:376::-;93069:21;:19;:21::i;:::-;93101:20;93124:13;;;;;;;;;;;93101:36;;93177:54;;;;;;;;93198:5;93177:54;;;;;;93224:5;93177:54;;;;;93148:12;:26;93161:12;93148:26;;;;;;;;;;;;;;;:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93258:14;93242:13;;:30;;;;;;;;;;;;;;;;;;93314:53;;;;;;;;93335:5;93314:53;;;;;;93361:4;93314:53;;;;;93283:12;:28;93296:14;93283:28;;;;;;;;;;;;;;;:84;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93058:317;92999:376;:::o;86275:31::-;;;;:::o;82407:695::-;82637:8;82619:15;:26;82615:99;;;82693:8;82669:33;;;;;;;;;;;:::i;:::-;;;;;;;;82615:99;82726:18;81727:95;82785:5;82792:7;82801:5;82808:16;82818:5;82808:9;:16::i;:::-;82826:8;82757:78;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;82747:89;;;;;;82726:110;;82849:12;82864:28;82881:10;82864:16;:28::i;:::-;82849:43;;82905:14;82922:28;82936:4;82942:1;82945;82948;82922:13;:28::i;:::-;82905:45;;82975:5;82965:15;;:6;:15;;;82961:90;;83025:6;83033:5;83004:35;;;;;;;;;;;;:::i;:::-;;;;;;;;82961:90;83063:31;83072:5;83079:7;83088:5;83063:8;:31::i;:::-;82604:498;;;82407:695;;;;;;;:::o;73398:142::-;73478:7;73505:11;:18;73517:5;73505:18;;;;;;;;;;;;;;;:27;73524:7;73505:27;;;;;;;;;;;;;;;;73498:34;;73398:142;;;;:::o;84926:96::-;85018:3;85005:1;84903:16;84982:25;;;;:::i;:::-;:40;;;;:::i;:::-;84926:96;:::o;65437:220::-;64390:13;:11;:13::i;:::-;65542:1:::1;65522:22;;:8;:22;;::::0;65518:93:::1;;65596:1;65568:31;;;;;;;;;;;:::i;:::-;;;;;;;;65518:93;65621:28;65640:8;65621:18;:28::i;:::-;65437:220:::0;:::o;93680:227::-;64390:13;:11;:13::i;:::-;93830:69:::1;;;;;;;;93851:7;93830:69;;;;;;93879:18;93830:69;;;;::::0;93805:12:::1;:22;93818:8;93805:22;;;;;;;;;;;;;;;:94;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93680:227:::0;;;:::o;62620:98::-;62673:7;62700:10;62693:17;;62620:98;:::o;78686:130::-;78771:37;78780:5;78787:7;78796:5;78803:4;78771:8;:37::i;:::-;78686:130;;;:::o;80402:487::-;80502:24;80529:25;80539:5;80546:7;80529:9;:25::i;:::-;80502:52;;80589:17;80569:16;:37;80565:317;;80646:5;80627:16;:24;80623:132;;;80706:7;80715:16;80733:5;80679:60;;;;;;;;;;;;;:::i;:::-;;;;;;;;80623:132;80798:57;80807:5;80814:7;80842:5;80823:16;:24;80849:5;80798:8;:57::i;:::-;80565:317;80491:398;80402:487;;;:::o;75261:308::-;75361:1;75345:18;;:4;:18;;;75341:88;;75414:1;75387:30;;;;;;;;;;;:::i;:::-;;;;;;;;75341:88;75457:1;75443:16;;:2;:16;;;75439:88;;75512:1;75483:32;;;;;;;;;;;:::i;:::-;;;;;;;;75439:88;75537:24;75545:4;75551:2;75555:5;75537:7;:24::i;:::-;75261:308;;;:::o;40465:268::-;40518:7;40559:11;40542:28;;40550:4;40542:28;;;:63;;;;;40591:14;40574:13;:31;40542:63;40538:188;;;40629:22;40622:29;;;;40538:188;40691:23;:21;:23::i;:::-;40684:30;;40465:268;;:::o;64669:166::-;64740:12;:10;:12::i;:::-;64729:23;;:7;:5;:7::i;:::-;:23;;;64725:103;;64803:12;:10;:12::i;:::-;64776:40;;;;;;;;;;;:::i;:::-;;;;;;;;64725:103;64669:166::o;65179:103::-;64390:13;:11;:13::i;:::-;65244:30:::1;65271:1;65244:18;:30::i;:::-;65179:103::o:0;2513:109::-;2573:7;2600;:14;2608:5;2600:14;;;;;;;;;;;;;;;;2593:21;;2513:109;;;:::o;42707:128::-;42753:13;42786:41;42813:13;42786:5;:26;;:41;;;;:::i;:::-;42779:48;;42707:128;:::o;43170:137::-;43219:13;43252:47;43282:16;43252:8;:29;;:47;;;;:::i;:::-;43245:54;;43170:137;:::o;77381:213::-;77471:1;77452:21;;:7;:21;;;77448:93;;77526:1;77497:32;;;;;;;;;;;:::i;:::-;;;;;;;;77448:93;77551:35;77567:1;77571:7;77580:5;77551:7;:35::i;:::-;77381:213;;:::o;98571:151::-;98665:8;98660:3;98653:21;98700:3;98695;98688:16;98288:160;98362:13;;;;;;;;;;;98348:27;;:10;:27;;;98344:97;;98392:37;98400:28;;;98392:7;:37::i;:::-;98344:97;98288:160::o;2743:402::-;2803:7;3110;:14;3118:5;3110:14;;;;;;;;;;;;;;;;:16;;;;;;;;;;;;3103:23;;2743:402;;;:::o;41564:178::-;41641:7;41668:66;41701:20;:18;:20::i;:::-;41723:10;41668:32;:66::i;:::-;41661:73;;41564:178;;;:::o;50304:264::-;50389:7;50410:17;50429:18;50449:16;50469:25;50480:4;50486:1;50489;50492;50469:10;:25::i;:::-;50409:85;;;;;;50505:28;50517:5;50524:8;50505:11;:28::i;:::-;50551:9;50544:16;;;;;50304:264;;;;;;:::o;65817:191::-;65891:16;65910:6;;;;;;;;;;;65891:25;;65936:8;65927:6;;:17;;;;;;;;;;;;;;;;;;65991:8;65960:40;;65981:8;65960:40;;;;;;;;;;;;65880:128;65817:191;:::o;79667:443::-;79797:1;79780:19;;:5;:19;;;79776:91;;79852:1;79823:32;;;;;;;;;;;:::i;:::-;;;;;;;;79776:91;79900:1;79881:21;;:7;:21;;;79877:92;;79954:1;79926:31;;;;;;;;;;;:::i;:::-;;;;;;;;79877:92;80009:5;79979:11;:18;79991:5;79979:18;;;;;;;;;;;;;;;:27;79998:7;79979:27;;;;;;;;;;;;;;;:35;;;;80029:9;80025:78;;;80076:7;80060:31;;80069:5;80060:31;;;80085:5;80060:31;;;;;;:::i;:::-;;;;;;;;80025:78;79667:443;;;;:::o;89354:1543::-;89448:14;89465:8;;;;;;;;;;;89448:25;;89484:14;89501:5;89484:22;;89517:27;89547:12;:18;89560:4;89547:18;;;;;;;;;;;;;;;89517:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89576:25;89604:12;:16;89617:2;89604:16;;;;;;;;;;;;;;;89576:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85395:42;89635:13;;:4;:13;;;:28;;;;85395:42;89652:11;;:2;:11;;;89635:28;89631:99;;;89680:38;89688:29;;;89680:7;:38::i;:::-;89631:99;89745:8;:26;;;89744:27;:56;;;;;89776:6;:24;;;89775:25;89744:56;89740:1106;;;89821:8;:15;;;89817:617;;;89861:9;89857:410;;;89895:17;89915:13;89925:2;89915:9;:13::i;:::-;89895:33;;85018:3;85005:1;84903:16;84982:25;;;;:::i;:::-;:40;;;;:::i;:::-;89967:5;89955:9;:17;;;;:::i;:::-;:49;89951:148;;;90033:42;90041:33;;;90033:7;:42::i;:::-;89951:148;85156:4;85143:1;84903:16;85120:25;;;;:::i;:::-;:41;;;;:::i;:::-;90125:5;:21;90121:127;;;90175:49;90183:40;;;90175:7;:49::i;:::-;90121:127;89872:395;89857:410;90287:11;90301:18;90313:5;90301:11;:18::i;:::-;90287:32;;90355:3;90347:5;:11;;;;:::i;:::-;90338:20;;90379:39;90393:4;90407;90414:3;90379:13;:39::i;:::-;89838:596;89817:617;90452:6;:13;;;90448:387;;;90490:9;90486:186;;;85296:4;85283:1;84903:16;85260:25;;;;:::i;:::-;:41;;;;:::i;:::-;90528:5;:22;90524:129;;;90579:50;90587:41;;;90579:7;:50::i;:::-;90524:129;90486:186;90690:11;90704:18;90716:5;90704:11;:18::i;:::-;90690:32;;90758:3;90750:5;:11;;;;:::i;:::-;90741:20;;90780:39;90794:4;90808;90815:3;90780:13;:39::i;:::-;90467:368;90448:387;89740:1106;90858:31;90872:4;90878:2;90882:6;90858:13;:31::i;:::-;89437:1460;;;;89354:1543;;;:::o;40741:181::-;40796:7;38657:95;40855:11;40868:14;40884:13;40907:4;40833:80;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;40823:91;;;;;;40816:98;;40741:181;:::o;11853:273::-;11947:13;9799:66;12006:17;;11996:5;11977:46;11973:146;;12047:15;12056:5;12047:8;:15::i;:::-;12040:22;;;;11973:146;12102:5;12095:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11853:273;;;;;:::o;36264:410::-;36357:14;36469:4;36463:11;36500:10;36495:3;36488:23;36548:15;36541:4;36536:3;36532:14;36525:39;36601:10;36594:4;36589:3;36585:14;36578:34;36651:4;36646:3;36636:20;36626:30;;36437:230;36264:410;;;;:::o;48609:1556::-;48740:7;48749:12;48763:7;49683:66;49678:1;49670:10;;:79;49666:166;;;49782:1;49786:30;49818:1;49766:54;;;;;;;;49666:166;49929:14;49946:24;49956:4;49962:1;49965;49968;49946:24;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49929:41;;50003:1;49985:20;;:6;:20;;;49981:115;;50038:1;50042:29;50081:1;50073:10;;50022:62;;;;;;;;;49981:115;50116:6;50124:20;50154:1;50146:10;;50108:49;;;;;;;48609:1556;;;;;;;;;:::o;50706:542::-;50802:20;50793:29;;;;;;;;:::i;:::-;;:5;:29;;;;;;;;:::i;:::-;;;50789:452;50839:7;50789:452;50900:29;50891:38;;;;;;;;:::i;:::-;;:5;:38;;;;;;;;:::i;:::-;;;50887:354;;50953:23;;;;;;;;;;;;;;50887:354;51007:35;50998:44;;;;;;;;:::i;:::-;;:5;:44;;;;;;;;:::i;:::-;;;50994:247;;51102:8;51094:17;;51066:46;;;;;;;;;;;:::i;:::-;;;;;;;;50994:247;51143:30;51134:39;;;;;;;;:::i;:::-;;:5;:39;;;;;;;;:::i;:::-;;;51130:111;;51220:8;51197:32;;;;;;;;;;;:::i;:::-;;;;;;;;51130:111;50706:542;;;:::o;96932:774::-;96987:7;97007:25;97035:16;;97007:44;;97087:1;97066:17;:22;97062:140;;97124:15;97105:16;:34;;;;97177:3;97171:2;97162:6;:11;;;;:::i;:::-;97161:19;;;;:::i;:::-;97154:26;;;;;97062:140;97212:26;97259:17;97241:15;:35;;;;:::i;:::-;97212:64;;97312:2;97291:18;:23;97287:116;;;97378:3;97372:2;97363:6;:11;;;;:::i;:::-;97362:19;;;;:::i;:::-;97355:26;;;;;;97287:116;97438:3;97417:18;:24;97413:117;;;97506:3;97501:1;97492:6;:10;;;;:::i;:::-;97491:18;;;;:::i;:::-;97484:25;;;;;;97413:117;97587:4;97566:18;:25;97562:92;;;97630:3;97625:1;97616:6;:10;;;;:::i;:::-;97615:18;;;;:::i;:::-;97608:25;;;;;;97562:92;97686:3;97681:1;97672:6;:10;;;;:::i;:::-;97671:18;;;;:::i;:::-;97664:25;;;;96932:774;;;;:::o;75893:1135::-;75999:1;75983:18;;:4;:18;;;75979:552;;76137:5;76121:12;;:21;;;;;;;:::i;:::-;;;;;;;;75979:552;;;76175:19;76197:9;:15;76207:4;76197:15;;;;;;;;;;;;;;;;76175:37;;76245:5;76231:11;:19;76227:117;;;76303:4;76309:11;76322:5;76278:50;;;;;;;;;;;;;:::i;:::-;;;;;;;;76227:117;76499:5;76485:11;:19;76467:9;:15;76477:4;76467:15;;;;;;;;;;;;;;;:37;;;;76160:371;75979:552;76561:1;76547:16;;:2;:16;;;76543:435;;76729:5;76713:12;;:21;;;;;;;;;;;76543:435;;;76946:5;76929:9;:13;76939:2;76929:13;;;;;;;;;;;;;;;;:22;;;;;;;;;;;76543:435;77010:2;76995:25;;77004:4;76995:25;;;77014:5;76995:25;;;;;;:::i;:::-;;;;;;;;75893:1135;;;:::o;10508:415::-;10567:13;10593:11;10607:16;10618:4;10607:10;:16::i;:::-;10593:30;;10713:17;10744:2;10733:14;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10713:34;;10838:3;10833;10826:16;10879:4;10872;10867:3;10863:14;10856:28;10912:3;10905:10;;;;10508:415;;;:::o;11000:251::-;11061:7;11081:14;11134:4;11125;11098:33;;:40;11081:57;;11162:2;11153:6;:11;11149:71;;;11188:20;;;;;;;;;;;;;;11149:71;11237:6;11230:13;;;11000:251;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;:::o;7:99:1:-;59:6;93:5;87:12;77:22;;7:99;;;:::o;112:169::-;196:11;230:6;225:3;218:19;270:4;265:3;261:14;246:29;;112:169;;;;:::o;287:246::-;368:1;378:113;392:6;389:1;386:13;378:113;;;477:1;472:3;468:11;462:18;458:1;453:3;449:11;442:39;414:2;411:1;407:10;402:15;;378:113;;;525:1;516:6;511:3;507:16;500:27;349:184;287:246;;;:::o;539:102::-;580:6;631:2;627:7;622:2;615:5;611:14;607:28;597:38;;539:102;;;:::o;647:377::-;735:3;763:39;796:5;763:39;:::i;:::-;818:71;882:6;877:3;818:71;:::i;:::-;811:78;;898:65;956:6;951:3;944:4;937:5;933:16;898:65;:::i;:::-;988:29;1010:6;988:29;:::i;:::-;983:3;979:39;972:46;;739:285;647:377;;;;:::o;1030:313::-;1143:4;1181:2;1170:9;1166:18;1158:26;;1230:9;1224:4;1220:20;1216:1;1205:9;1201:17;1194:47;1258:78;1331:4;1322:6;1258:78;:::i;:::-;1250:86;;1030:313;;;;:::o;1430:117::-;1539:1;1536;1529:12;1676:126;1713:7;1753:42;1746:5;1742:54;1731:65;;1676:126;;;:::o;1808:96::-;1845:7;1874:24;1892:5;1874:24;:::i;:::-;1863:35;;1808:96;;;:::o;1910:122::-;1983:24;2001:5;1983:24;:::i;:::-;1976:5;1973:35;1963:63;;2022:1;2019;2012:12;1963:63;1910:122;:::o;2038:139::-;2084:5;2122:6;2109:20;2100:29;;2138:33;2165:5;2138:33;:::i;:::-;2038:139;;;;:::o;2183:77::-;2220:7;2249:5;2238:16;;2183:77;;;:::o;2266:122::-;2339:24;2357:5;2339:24;:::i;:::-;2332:5;2329:35;2319:63;;2378:1;2375;2368:12;2319:63;2266:122;:::o;2394:139::-;2440:5;2478:6;2465:20;2456:29;;2494:33;2521:5;2494:33;:::i;:::-;2394:139;;;;:::o;2539:474::-;2607:6;2615;2664:2;2652:9;2643:7;2639:23;2635:32;2632:119;;;2670:79;;:::i;:::-;2632:119;2790:1;2815:53;2860:7;2851:6;2840:9;2836:22;2815:53;:::i;:::-;2805:63;;2761:117;2917:2;2943:53;2988:7;2979:6;2968:9;2964:22;2943:53;:::i;:::-;2933:63;;2888:118;2539:474;;;;;:::o;3019:90::-;3053:7;3096:5;3089:13;3082:21;3071:32;;3019:90;;;:::o;3115:109::-;3196:21;3211:5;3196:21;:::i;:::-;3191:3;3184:34;3115:109;;:::o;3230:210::-;3317:4;3355:2;3344:9;3340:18;3332:26;;3368:65;3430:1;3419:9;3415:17;3406:6;3368:65;:::i;:::-;3230:210;;;;:::o;3446:118::-;3533:24;3551:5;3533:24;:::i;:::-;3528:3;3521:37;3446:118;;:::o;3570:222::-;3663:4;3701:2;3690:9;3686:18;3678:26;;3714:71;3782:1;3771:9;3767:17;3758:6;3714:71;:::i;:::-;3570:222;;;;:::o;3798:619::-;3875:6;3883;3891;3940:2;3928:9;3919:7;3915:23;3911:32;3908:119;;;3946:79;;:::i;:::-;3908:119;4066:1;4091:53;4136:7;4127:6;4116:9;4112:22;4091:53;:::i;:::-;4081:63;;4037:117;4193:2;4219:53;4264:7;4255:6;4244:9;4240:22;4219:53;:::i;:::-;4209:63;;4164:118;4321:2;4347:53;4392:7;4383:6;4372:9;4368:22;4347:53;:::i;:::-;4337:63;;4292:118;3798:619;;;;;:::o;4423:86::-;4458:7;4498:4;4491:5;4487:16;4476:27;;4423:86;;;:::o;4515:112::-;4598:22;4614:5;4598:22;:::i;:::-;4593:3;4586:35;4515:112;;:::o;4633:214::-;4722:4;4760:2;4749:9;4745:18;4737:26;;4773:67;4837:1;4826:9;4822:17;4813:6;4773:67;:::i;:::-;4633:214;;;;:::o;4853:77::-;4890:7;4919:5;4908:16;;4853:77;;;:::o;4936:118::-;5023:24;5041:5;5023:24;:::i;:::-;5018:3;5011:37;4936:118;;:::o;5060:222::-;5153:4;5191:2;5180:9;5176:18;5168:26;;5204:71;5272:1;5261:9;5257:17;5248:6;5204:71;:::i;:::-;5060:222;;;;:::o;5288:118::-;5375:24;5393:5;5375:24;:::i;:::-;5370:3;5363:37;5288:118;;:::o;5412:222::-;5505:4;5543:2;5532:9;5528:18;5520:26;;5556:71;5624:1;5613:9;5609:17;5600:6;5556:71;:::i;:::-;5412:222;;;;:::o;5640:329::-;5699:6;5748:2;5736:9;5727:7;5723:23;5719:32;5716:119;;;5754:79;;:::i;:::-;5716:119;5874:1;5899:53;5944:7;5935:6;5924:9;5920:22;5899:53;:::i;:::-;5889:63;;5845:117;5640:329;;;;:::o;5975:99::-;6046:21;6061:5;6046:21;:::i;:::-;6041:3;6034:34;5975:99;;:::o;6144:518::-;6299:4;6294:3;6290:14;6388:4;6381:5;6377:16;6371:23;6407:57;6458:4;6453:3;6449:14;6435:12;6407:57;:::i;:::-;6314:160;6569:4;6562:5;6558:16;6552:23;6588:57;6639:4;6634:3;6630:14;6616:12;6588:57;:::i;:::-;6484:171;6268:394;6144:518;;:::o;6668:338::-;6819:4;6857:2;6846:9;6842:18;6834:26;;6870:129;6996:1;6985:9;6981:17;6972:6;6870:129;:::i;:::-;6668:338;;;;:::o;7012:116::-;7082:21;7097:5;7082:21;:::i;:::-;7075:5;7072:32;7062:60;;7118:1;7115;7108:12;7062:60;7012:116;:::o;7134:133::-;7177:5;7215:6;7202:20;7193:29;;7231:30;7255:5;7231:30;:::i;:::-;7134:133;;;;:::o;7273:323::-;7329:6;7378:2;7366:9;7357:7;7353:23;7349:32;7346:119;;;7384:79;;:::i;:::-;7346:119;7504:1;7529:50;7571:7;7562:6;7551:9;7547:22;7529:50;:::i;:::-;7519:60;;7475:114;7273:323;;;;:::o;7602:149::-;7638:7;7678:66;7671:5;7667:78;7656:89;;7602:149;;;:::o;7757:115::-;7842:23;7859:5;7842:23;:::i;:::-;7837:3;7830:36;7757:115;;:::o;7878:114::-;7945:6;7979:5;7973:12;7963:22;;7878:114;;;:::o;7998:184::-;8097:11;8131:6;8126:3;8119:19;8171:4;8166:3;8162:14;8147:29;;7998:184;;;;:::o;8188:132::-;8255:4;8278:3;8270:11;;8308:4;8303:3;8299:14;8291:22;;8188:132;;;:::o;8326:108::-;8403:24;8421:5;8403:24;:::i;:::-;8398:3;8391:37;8326:108;;:::o;8440:179::-;8509:10;8530:46;8572:3;8564:6;8530:46;:::i;:::-;8608:4;8603:3;8599:14;8585:28;;8440:179;;;;:::o;8625:113::-;8695:4;8727;8722:3;8718:14;8710:22;;8625:113;;;:::o;8774:732::-;8893:3;8922:54;8970:5;8922:54;:::i;:::-;8992:86;9071:6;9066:3;8992:86;:::i;:::-;8985:93;;9102:56;9152:5;9102:56;:::i;:::-;9181:7;9212:1;9197:284;9222:6;9219:1;9216:13;9197:284;;;9298:6;9292:13;9325:63;9384:3;9369:13;9325:63;:::i;:::-;9318:70;;9411:60;9464:6;9411:60;:::i;:::-;9401:70;;9257:224;9244:1;9241;9237:9;9232:14;;9197:284;;;9201:14;9497:3;9490:10;;8898:608;;;8774:732;;;;:::o;9512:1215::-;9861:4;9899:3;9888:9;9884:19;9876:27;;9913:69;9979:1;9968:9;9964:17;9955:6;9913:69;:::i;:::-;10029:9;10023:4;10019:20;10014:2;10003:9;9999:18;9992:48;10057:78;10130:4;10121:6;10057:78;:::i;:::-;10049:86;;10182:9;10176:4;10172:20;10167:2;10156:9;10152:18;10145:48;10210:78;10283:4;10274:6;10210:78;:::i;:::-;10202:86;;10298:72;10366:2;10355:9;10351:18;10342:6;10298:72;:::i;:::-;10380:73;10448:3;10437:9;10433:19;10424:6;10380:73;:::i;:::-;10463;10531:3;10520:9;10516:19;10507:6;10463:73;:::i;:::-;10584:9;10578:4;10574:20;10568:3;10557:9;10553:19;10546:49;10612:108;10715:4;10706:6;10612:108;:::i;:::-;10604:116;;9512:1215;;;;;;;;;;:::o;10733:474::-;10801:6;10809;10858:2;10846:9;10837:7;10833:23;10829:32;10826:119;;;10864:79;;:::i;:::-;10826:119;10984:1;11009:53;11054:7;11045:6;11034:9;11030:22;11009:53;:::i;:::-;10999:63;;10955:117;11111:2;11137:53;11182:7;11173:6;11162:9;11158:22;11137:53;:::i;:::-;11127:63;;11082:118;10733:474;;;;;:::o;11213:118::-;11284:22;11300:5;11284:22;:::i;:::-;11277:5;11274:33;11264:61;;11321:1;11318;11311:12;11264:61;11213:118;:::o;11337:135::-;11381:5;11419:6;11406:20;11397:29;;11435:31;11460:5;11435:31;:::i;:::-;11337:135;;;;:::o;11478:122::-;11551:24;11569:5;11551:24;:::i;:::-;11544:5;11541:35;11531:63;;11590:1;11587;11580:12;11531:63;11478:122;:::o;11606:139::-;11652:5;11690:6;11677:20;11668:29;;11706:33;11733:5;11706:33;:::i;:::-;11606:139;;;;:::o;11751:1199::-;11862:6;11870;11878;11886;11894;11902;11910;11959:3;11947:9;11938:7;11934:23;11930:33;11927:120;;;11966:79;;:::i;:::-;11927:120;12086:1;12111:53;12156:7;12147:6;12136:9;12132:22;12111:53;:::i;:::-;12101:63;;12057:117;12213:2;12239:53;12284:7;12275:6;12264:9;12260:22;12239:53;:::i;:::-;12229:63;;12184:118;12341:2;12367:53;12412:7;12403:6;12392:9;12388:22;12367:53;:::i;:::-;12357:63;;12312:118;12469:2;12495:53;12540:7;12531:6;12520:9;12516:22;12495:53;:::i;:::-;12485:63;;12440:118;12597:3;12624:51;12667:7;12658:6;12647:9;12643:22;12624:51;:::i;:::-;12614:61;;12568:117;12724:3;12751:53;12796:7;12787:6;12776:9;12772:22;12751:53;:::i;:::-;12741:63;;12695:119;12853:3;12880:53;12925:7;12916:6;12905:9;12901:22;12880:53;:::i;:::-;12870:63;;12824:119;11751:1199;;;;;;;;;;:::o;12956:607::-;13027:6;13035;13043;13092:2;13080:9;13071:7;13067:23;13063:32;13060:119;;;13098:79;;:::i;:::-;13060:119;13218:1;13243:53;13288:7;13279:6;13268:9;13264:22;13243:53;:::i;:::-;13233:63;;13189:117;13345:2;13371:50;13413:7;13404:6;13393:9;13389:22;13371:50;:::i;:::-;13361:60;;13316:115;13470:2;13496:50;13538:7;13529:6;13518:9;13514:22;13496:50;:::i;:::-;13486:60;;13441:115;12956:607;;;;;:::o;13569:180::-;13617:77;13614:1;13607:88;13714:4;13711:1;13704:15;13738:4;13735:1;13728:15;13755:320;13799:6;13836:1;13830:4;13826:12;13816:22;;13883:1;13877:4;13873:12;13904:18;13894:81;;13960:4;13952:6;13948:17;13938:27;;13894:81;14022:2;14014:6;14011:14;13991:18;13988:38;13985:84;;14041:18;;:::i;:::-;13985:84;13806:269;13755:320;;;:::o;14081:180::-;14129:77;14126:1;14119:88;14226:4;14223:1;14216:15;14250:4;14247:1;14240:15;14267:410;14307:7;14330:20;14348:1;14330:20;:::i;:::-;14325:25;;14364:20;14382:1;14364:20;:::i;:::-;14359:25;;14419:1;14416;14412:9;14441:30;14459:11;14441:30;:::i;:::-;14430:41;;14620:1;14611:7;14607:15;14604:1;14601:22;14581:1;14574:9;14554:83;14531:139;;14650:18;;:::i;:::-;14531:139;14315:362;14267:410;;;;:::o;14683:180::-;14731:77;14728:1;14721:88;14828:4;14825:1;14818:15;14852:4;14849:1;14842:15;14869:185;14909:1;14926:20;14944:1;14926:20;:::i;:::-;14921:25;;14960:20;14978:1;14960:20;:::i;:::-;14955:25;;14999:1;14989:35;;15004:18;;:::i;:::-;14989:35;15046:1;15043;15039:9;15034:14;;14869:185;;;;:::o;15060:180::-;15108:77;15105:1;15098:88;15205:4;15202:1;15195:15;15229:4;15226:1;15219:15;15246:147;15347:11;15384:3;15369:18;;15246:147;;;;:::o;15399:114::-;;:::o;15519:398::-;15678:3;15699:83;15780:1;15775:3;15699:83;:::i;:::-;15692:90;;15791:93;15880:3;15791:93;:::i;:::-;15909:1;15904:3;15900:11;15893:18;;15519:398;;;:::o;15923:379::-;16107:3;16129:147;16272:3;16129:147;:::i;:::-;16122:154;;16293:3;16286:10;;15923:379;;;:::o;16308:221::-;16448:34;16444:1;16436:6;16432:14;16425:58;16517:4;16512:2;16504:6;16500:15;16493:29;16308:221;:::o;16535:366::-;16677:3;16698:67;16762:2;16757:3;16698:67;:::i;:::-;16691:74;;16774:93;16863:3;16774:93;:::i;:::-;16892:2;16887:3;16883:12;16876:19;;16535:366;;;:::o;16907:419::-;17073:4;17111:2;17100:9;17096:18;17088:26;;17160:9;17154:4;17150:20;17146:1;17135:9;17131:17;17124:47;17188:131;17314:4;17188:131;:::i;:::-;17180:139;;16907:419;;;:::o;17332:143::-;17389:5;17420:6;17414:13;17405:22;;17436:33;17463:5;17436:33;:::i;:::-;17332:143;;;;:::o;17481:351::-;17551:6;17600:2;17588:9;17579:7;17575:23;17571:32;17568:119;;;17606:79;;:::i;:::-;17568:119;17726:1;17751:64;17807:7;17798:6;17787:9;17783:22;17751:64;:::i;:::-;17741:74;;17697:128;17481:351;;;;:::o;17838:332::-;17959:4;17997:2;17986:9;17982:18;17974:26;;18010:71;18078:1;18067:9;18063:17;18054:6;18010:71;:::i;:::-;18091:72;18159:2;18148:9;18144:18;18135:6;18091:72;:::i;:::-;17838:332;;;;;:::o;18176:137::-;18230:5;18261:6;18255:13;18246:22;;18277:30;18301:5;18277:30;:::i;:::-;18176:137;;;;:::o;18319:345::-;18386:6;18435:2;18423:9;18414:7;18410:23;18406:32;18403:119;;;18441:79;;:::i;:::-;18403:119;18561:1;18586:61;18639:7;18630:6;18619:9;18615:22;18586:61;:::i;:::-;18576:71;;18532:125;18319:345;;;;:::o;18670:775::-;18903:4;18941:3;18930:9;18926:19;18918:27;;18955:71;19023:1;19012:9;19008:17;18999:6;18955:71;:::i;:::-;19036:72;19104:2;19093:9;19089:18;19080:6;19036:72;:::i;:::-;19118;19186:2;19175:9;19171:18;19162:6;19118:72;:::i;:::-;19200;19268:2;19257:9;19253:18;19244:6;19200:72;:::i;:::-;19282:73;19350:3;19339:9;19335:19;19326:6;19282:73;:::i;:::-;19365;19433:3;19422:9;19418:19;19409:6;19365:73;:::i;:::-;18670:775;;;;;;;;;:::o;19451:332::-;19572:4;19610:2;19599:9;19595:18;19587:26;;19623:71;19691:1;19680:9;19676:17;19667:6;19623:71;:::i;:::-;19704:72;19772:2;19761:9;19757:18;19748:6;19704:72;:::i;:::-;19451:332;;;;;:::o;19789:442::-;19938:4;19976:2;19965:9;19961:18;19953:26;;19989:71;20057:1;20046:9;20042:17;20033:6;19989:71;:::i;:::-;20070:72;20138:2;20127:9;20123:18;20114:6;20070:72;:::i;:::-;20152;20220:2;20209:9;20205:18;20196:6;20152:72;:::i;:::-;19789:442;;;;;;:::o;20237:191::-;20277:3;20296:20;20314:1;20296:20;:::i;:::-;20291:25;;20330:20;20348:1;20330:20;:::i;:::-;20325:25;;20373:1;20370;20366:9;20359:16;;20394:3;20391:1;20388:10;20385:36;;;20401:18;;:::i;:::-;20385:36;20237:191;;;;:::o;20434:194::-;20474:4;20494:20;20512:1;20494:20;:::i;:::-;20489:25;;20528:20;20546:1;20528:20;:::i;:::-;20523:25;;20572:1;20569;20565:9;20557:17;;20596:1;20590:4;20587:11;20584:37;;;20601:18;;:::i;:::-;20584:37;20434:194;;;;:::o;20634:664::-;20839:4;20877:3;20866:9;20862:19;20854:27;;20891:71;20959:1;20948:9;20944:17;20935:6;20891:71;:::i;:::-;20972:72;21040:2;21029:9;21025:18;21016:6;20972:72;:::i;:::-;21054;21122:2;21111:9;21107:18;21098:6;21054:72;:::i;:::-;21136;21204:2;21193:9;21189:18;21180:6;21136:72;:::i;:::-;21218:73;21286:3;21275:9;21271:19;21262:6;21218:73;:::i;:::-;20634:664;;;;;;;;:::o;21304:545::-;21477:4;21515:3;21504:9;21500:19;21492:27;;21529:71;21597:1;21586:9;21582:17;21573:6;21529:71;:::i;:::-;21610:68;21674:2;21663:9;21659:18;21650:6;21610:68;:::i;:::-;21688:72;21756:2;21745:9;21741:18;21732:6;21688:72;:::i;:::-;21770;21838:2;21827:9;21823:18;21814:6;21770:72;:::i;:::-;21304:545;;;;;;;:::o;21855:180::-;21903:77;21900:1;21893:88;22000:4;21997:1;21990:15;22024:4;22021:1;22014:15

Swarm Source

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