Hawg (HAWG)

Overview

TokenID

9903

Total Transfers

-

Market

Onchain Market Cap

-

Circulating Supply Market Cap

-
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
Hawg404

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
No with 200 runs

Other Settings:
paris EvmVersion
File 1 of 6 : Hawg404.sol
// SPDX-License-Identifier: MIT
// Hawg404 The first ERC404 on Sonic prev. GOAT404 the first ERC404 on Fantom
/*
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%=..................:%#.............:%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+.+%@@@@@@@@@@@@@@@@@@:=%+:#%@@@@@@@@@-=%@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@----=#@@@@@@@@@@@@@@@@@@%-+#=-@@@@@@@@@@#-+#@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@%*********=#@@@@@@@@@@@@@@@@@@@*=%@@@@@@@@@@@@@=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@%**+========*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@%++++#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@+- :==#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@######+-%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@+-+#@@@@@@@@@@@@@@@+-----------------=@@@#=------:.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@*:*%@@@@@@@@@@@@@@@*:#%%%%%%%%%%%%%%%%%#:::=#%%%%%%=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@%:+@@@@@@@@@@@@@@@@-.+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@+..-@@@@#------+@@@@=.%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@%.+@@@@@@@*.*%%%%*-#@@=.%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.-@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ :@@@@@@@@@*.#@@@@*.*@@=.%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.-@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@=.....:#@@@@@*.#@@@@*....*@@@@@@@@@@@@@@@@@@@@@@@@@%-....:@@*...-@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@%#==@@@@#-*#@@@@@@@@@@@@+. .@@#       .=@@@@@@%+:.. .##=.  :##%@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@+:#@@@@@@@*++*@@@@@@@@@@#++++++++++++++#@@@@@@@@%+++++-.-+++++++#@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@%-+#@@@@@@@@@@.:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.*@@@@@#:+@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@%#:+@@@@@@@@@@@.:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#:*%%%%%#-+@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@%%:=@@@@@@@@@@@@@.:@@@@@@@@@@@@%%%%%%%%%@@@@@@@@@@@@@@@@@@@@@+:::..=%@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@%+-@@@@@@@@@@@@@@@.:@@@@@@@@@@@@-.------:+#######################*-*@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@#*=#@@@@@@@@@@@@@@@@.:@@@@@@@@@@@@-.######+-----------------------.-@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@-:=+++*@@@@@@@@@@@@@.:@@@@@@@@@@@@*++++++=-+++++++++++++++++++++++.-@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@#******=*@@@@@@@@@@@.:@@@@@@@@@@@@@@@@@@@%#***********************.-@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@:-%%@@@@@@@@@@@%#-+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+-#%@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@.:@@@@@@@@@#:......:*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@=.@@@@@@%:...=%@@@@@@%=...............=@@@@@@@@@@@@@@@@=.....*@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@=.@@@@@--%@@@@@@@@@@@@@@@@@@@@@@@@@@@@*:...............#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@=.@@@+:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@#:+%%#:+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@%=---=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
*/
pragma solidity ^0.8.18;

import "./S404.sol";
import "./Libraries.sol";

contract Hawg404 is S404, ERC165 {
    string public baseTokenURI; // https://ipfs.io/ipfs/QmfZr7DqU5cVnt8d1Hhtt5CujD25xa8uBFe9kq3tRzapVB/

    uint256 public maxMintable;
    uint256 public maxMintPerTx;

    uint256 public price;

   

    mapping(uint256 => mapping(address => uint256)) public phaseMintsRemaining;

    uint256 public phases;
    uint256 public phaseDuration;
    bool public paused;

    bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;

    bool private _mintActive;
    uint256 public startTime;

    constructor(
        string memory name,
        string memory symbol,
        uint8 decimals,
        uint256 supply, 
        string memory _baseTokenURI,
        address _owner,
        uint256 _startTime
      
    ) S404(name, symbol, decimals, supply, _owner) {
        balanceOf[_owner] = 0 ether;

        whitelist[_owner] = true;
        price = 100 ether;

        maxMintable = supply; 

        _mintActive = false;
        maxMintPerTx = 1000;
        startTime = _startTime;
        paused = false;
      

        baseTokenURI = _baseTokenURI; 

        phaseDuration = 3600; // 1 hour

        phases = 2;
    }

    function tokenURI(uint256 id) public view override returns (string memory) {
        return string.concat(baseTokenURI, Strings.toString(id), ".json"); 
    }

    function hasPhaseAccess(
        uint256 phase,
        address account
    ) public view returns (bool) {
        return phaseMintsRemaining[phase][account] > 0;
    }

    function canMintAmountInPhase(
        uint256 phase,
        address account,
        uint256 quantity
    ) public view returns (bool) {
        return phaseMintsRemaining[phase][account] >= quantity;
    }

    function activePhase() public view returns (uint256) {
        if (!mintHasStarted()) {
            return 0;
        } else {
            uint256 secondsPastStart = block.timestamp - startTime;
            uint256 phase = (secondsPastStart / phaseDuration) + 1;

            if (phase > phases) {
                return phases + 1; // +1 for public
            } else {
                return phase;
            }
        }
    }

    function mintHasStarted() public view returns (bool) {
        return block.timestamp >= startTime;
    }

    function secondsUntilStart() public view returns (uint256) {
        if (!mintHasStarted()) {
            return startTime - block.timestamp;
        } else {
            return 0;
        }
    }

    function mintActive() public view returns (bool) {
        return _mintActive || (block.timestamp >= startTime); // use timer w/ability to override
    }

  function mint(uint256 quantity) public payable {
    require(mintActive(), "Minting is not active.");
    require(!paused);

    require(quantity <= maxMintPerTx, "Cannot mint that many at once.");
    require(minted + quantity <= maxMintable, "Finished minting.");
    require(msg.value >= (quantity * price), "Not enough FTM sent.");

    for (uint256 phase = 1; phase <= phases; phase++) {
      if (activePhase() == phase) {
        require(
          canMintAmountInPhase(phase, msg.sender, quantity),
          string.concat("Currently in phase ", Strings.toString(phase), ".")
        );
        phaseMintsRemaining[phase][msg.sender] -= quantity;
      }
    }

    if (msg.value > 0) {
      payable(owner).transfer(msg.value);
    }

    _mint(msg.sender, quantity);
  }

    function supportsInterface(
        bytes4 interfaceId
    ) public view virtual override(ERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            interfaceId == _INTERFACE_ID_ERC2981 ||
            super.supportsInterface(interfaceId);
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, amount);

        if (activePhase() <= phases) {
            // still within a mint phase
            require(
                from == owner || to == owner,
                "Cannot transfer until mint enters public."
            );
            return;
        } else if (
            block.timestamp < (startTime + (phases * phaseDuration) + 180)
        ) {
            // 3 minutes of anti-whale when trading goes live
            require(
                balanceOf[to] <= ((5 * totalSupply) / 1000),
                "No more than 0.5% at this stage."
            );
            return;
        }
    }

    // owner
 function ownerMint(address recipient, uint256 quantity) public onlyOwner {
    _mint(recipient, quantity);
  }

    function grantPhaseAccess(
        uint256 phase,
        address[] memory accounts,
        uint256 quantity
    ) public onlyOwner {
        for (uint256 i = 0; i < accounts.length; i++) {
            phaseMintsRemaining[phase][accounts[i]] += quantity;
        }
    }

    function setPaused(bool _paused) public onlyOwner {
        paused = _paused;
    }

    function setMintActive(bool mintActive_) public onlyOwner {
        _mintActive = mintActive_;
    }

    function setStartTime(uint256 _startTime) public onlyOwner {
        startTime = _startTime;
    }

    function setBaseURI(string memory _baseURI) public onlyOwner {
        baseTokenURI = _baseURI;
    }

    function setMaxPerTx(uint256 _maxMintPerTx) public onlyOwner {
        maxMintPerTx = _maxMintPerTx;
    }

    function setPrice(uint256 _price) public onlyOwner {
        price = _price;
    }
}

File 2 of 6 : ERC721Receiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

abstract contract ERC721Receiver {
  function onERC721Received(
    address,
    address,
    uint256,
    bytes calldata
  ) external virtual returns (bytes4) {
    return ERC721Receiver.onERC721Received.selector;
  }
}

File 3 of 6 : IERC165.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

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

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

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

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

File 4 of 6 : Libraries.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "./IERC165.sol";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)

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

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

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}
interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
}

File 5 of 6 : ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

abstract contract Ownable {
    event OwnershipTransferred(address indexed user, address indexed newOwner);

    error Unauthorized();
    error InvalidOwner();

    address public owner;

    modifier onlyOwner() virtual {
        if (msg.sender != owner) revert Unauthorized();

        _;
    }

    constructor(address _owner) {
        if (_owner == address(0)) revert InvalidOwner();

        owner = _owner;

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

    function transferOwnership(address _owner) public virtual onlyOwner {
        if (_owner == address(0)) revert InvalidOwner();

        owner = _owner;

        emit OwnershipTransferred(msg.sender, _owner);
    }

    function revokeOwnership() public virtual onlyOwner {
        owner = address(0);

        emit OwnershipTransferred(msg.sender, address(0));
    }
}

File 6 of 6 : S404.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "./ownable.sol";
import "./ERC721Receiver.sol";

abstract contract S404 is Ownable {
  // Events
  event ERC20Transfer(address indexed from, address indexed to, uint256 amount);

  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 amount
  );

  event Transfer(address indexed from, address indexed to, uint256 indexed id);

  event ERC721Approval(
    address indexed owner,
    address indexed spender,
    uint256 indexed id
  );

  event ApprovalForAll(
    address indexed owner,
    address indexed operator,
    bool approved
  );

  // Errors
  error NotFound();
  error AlreadyExists();
  error InvalidRecipient();
  error InvalidSender();
  error UnsafeRecipient();

  // Metadata
  /// @dev Token name
  string public name;

  /// @dev Token symbol
  string public symbol;

  /// @dev Decimals for fractional representation
  uint8 public immutable decimals;

  /// @dev Total supply in fractionalized representation
  uint256 public immutable totalSupply;

  /// @dev Total supply in NFT representation
  uint256 public immutable totalNativeSupply;

  /// @dev Current mint counter, monotonically increasing to ensure accurate ownership
  uint256 public minted;

  // Mappings
  /// @dev Balance of user in fractional representation
  mapping(address => uint256) public balanceOf;

  /// @dev Allowance of user in fractional representation
  mapping(address => mapping(address => uint256)) public allowance;

  /// @dev Approval in native representaion
  mapping(uint256 => address) public getApproved;

  /// @dev Approval for all in native representation
  mapping(address => mapping(address => bool)) public isApprovedForAll;

  /// @dev Owner of id in native representation
  mapping(uint256 => address) internal _ownerOf;

  /// @dev Array of owned ids in native representation
  mapping(address => uint256[]) internal _owned;
  mapping(address => uint256[]) internal _contractOwned;

  /// @dev Tracks indices for the _owned mapping
  mapping(uint256 => uint256) internal _ownedIndex;

  /// @dev Addresses whitelisted from minting / burning for gas savings (pairs, routers, etc)
  mapping(address => bool) public whitelist;

  /// @dev Holds the IDs of NFTs that have been burned so that they can be re-used
  uint256[] public availableIds;

  // Constructor
  constructor(
    string memory _name,
    string memory _symbol,
    uint8 _decimals,
    uint256 _totalNativeSupply,
    address _owner
  ) Ownable(_owner) {
    name = _name;
    symbol = _symbol;
    decimals = _decimals;
    totalNativeSupply = _totalNativeSupply;
    totalSupply = _totalNativeSupply * (10 ** decimals);
  }

  /// @notice Initialization function to set pairs / etc
  ///         saving gas by avoiding mint / burn on unnecessary targets
  function setWhitelist(address target, bool state) public onlyOwner {
    whitelist[target] = state;
  }

  /// @notice Function to find owner of a given native token
  function ownerOf(uint256 id) public view virtual returns (address owner) {
    owner = _ownerOf[id];

    if (owner == address(0)) {
      revert NotFound();
    }
  }

  function totalAvailableIds() public view returns (uint256) {
    return availableIds.length;
  }

  function totalNFTsOwned(address owner) public view returns (uint256) {
    return _owned[owner].length;
  }

  /// @notice tokenURI must be implemented by child contract
  function tokenURI(uint256 id) public view virtual returns (string memory);

  /// @notice Function for token approvals
  /// @dev This function assumes id / native if amount less than or equal to current max id
  function approve(
    address spender,
    uint256 amountOrId
  ) public virtual returns (bool) {
    if (amountOrId <= minted && amountOrId > 0) {
      address owner = _ownerOf[amountOrId];

      if (msg.sender != owner && !isApprovedForAll[owner][msg.sender]) {
        revert Unauthorized();
      }

      getApproved[amountOrId] = spender;

      emit Approval(owner, spender, amountOrId);
    } else {
      allowance[msg.sender][spender] = amountOrId;

      emit Approval(msg.sender, spender, amountOrId);
    }

    return true;
  }

  /// @notice Function native approvals
  function setApprovalForAll(address operator, bool approved) public virtual {
    isApprovedForAll[msg.sender][operator] = approved;

    emit ApprovalForAll(msg.sender, operator, approved);
  }

  /// @notice Function for mixed transfers
  /// @dev This function assumes id / native if amount less than or equal to current max id
  function transferFrom(
    address from,
    address to,
    uint256 amount
  ) public returns (bool) {
    uint256 allowed = allowance[from][msg.sender];

    require(allowed >= amount, "Not enough allowance.");

    if (allowed != type(uint256).max)
      allowance[from][msg.sender] = allowed - amount;

    _transfer(from, to, amount);
    return true;
  }

  /// @notice Function for fractional transfers
  function transfer(address to, uint256 amount) public virtual returns (bool) {
    return _transfer(msg.sender, to, amount);
  }

  /// @notice Function for native transfers with contract support
  function safeTransferFrom(
    address from,
    address to,
    uint256 id
  ) public virtual {
    _nftTransferFrom(msg.sender, from, to, id);

    if (
      to.code.length != 0 &&
      ERC721Receiver(to).onERC721Received(msg.sender, from, id, "") !=
      ERC721Receiver.onERC721Received.selector
    ) {
      revert UnsafeRecipient();
    }
  }

  /// @notice Function for native transfers with contract support and callback data
  function safeTransferFrom(
    address from,
    address to,
    uint256 id,
    bytes calldata data
  ) public virtual {
    _nftTransferFrom(msg.sender, from, to, id);

    if (
      to.code.length != 0 &&
      ERC721Receiver(to).onERC721Received(msg.sender, from, id, data) !=
      ERC721Receiver.onERC721Received.selector
    ) {
      revert UnsafeRecipient();
    }
  }



  /// @notice Internal function for fractional transfers
  function _transfer(
    address from,
    address to,
    uint256 amount
  ) internal returns (bool) {
    _beforeTokenTransfer(from, to, amount);

    uint256 unit = _getUnit();
    uint256 balanceBeforeSender = balanceOf[from];
    uint256 balanceBeforeReceiver = balanceOf[to];

    if (_isContract(from)) {
      uint256 tokenBalance = balanceBeforeSender -
        (_contractOwned[from].length * unit);
      require(tokenBalance >= amount, "Not enough token balance.");
    }

    balanceOf[from] -= amount;
    unchecked {
      balanceOf[to] += amount;
    }

    // Skip burn for certain addresses to save gas
    // Skip minting to smart contracts
    if (!_shouldSkip(from) || _owned[from].length > 0) {
      uint256 nftsToBurn = (balanceBeforeSender / unit) -
        (balanceOf[from] / unit);
      for (uint256 i = 0; i < nftsToBurn; i++) {
        _burnNFT(from);
      }
    }

    // Skip minting for certain addresses to save gas
    // Skip burning from smart contracts
    if (!_shouldSkip(to)) {
      uint256 nftsToMint = (balanceOf[to] / unit) -
        (balanceBeforeReceiver / unit);
      for (uint256 i = 0; i < nftsToMint; i++) {
        _mintNFT(to);
      }
    }

    emit ERC20Transfer(from, to, amount);
    return true;
  }

  function _mint(address recipient, uint256 quantity) internal {
    balanceOf[recipient] += quantity * _getUnit();

    for (uint256 index = 0; index < quantity; index++) {
      _mintNFT(recipient);
    }
  }

  function _nftTransferFrom(
    address msgSender,
    address from,
    address to,
    uint256 id
  ) internal {
    require(from == _ownerOf[id], "Sender is not owner of NFT.");
    require(to != address(0), "Cannot send to null address.");
    require(
      msgSender == from ||
        isApprovedForAll[from][msgSender] ||
        msgSender == getApproved[id],
      "Operator is not approved."
    );

    balanceOf[from] -= _getUnit();
    unchecked {
      balanceOf[to] += _getUnit();
    }

    _removeSpecificNFT(from, id);
    _deliverNFT(to, id);

    emit Transfer(from, to, id);
    emit ERC20Transfer(from, to, _getUnit());
  }

  // Internal utility logic
  function _getUnit() internal view returns (uint256) {
    return 10 ** decimals;
  }

  function _mintNFT(address to) internal virtual {
    if (to == address(0)) {
      revert InvalidRecipient();
    }

    uint256 id;

    if (availableIds.length == 0) {
      unchecked {
        minted++;
      }
      require(
        minted <= totalNativeSupply,
        "Cannot mint more than given supply."
      );
      id = minted;
    } else {
      id = availableIds[availableIds.length - 1];
      availableIds.pop();
    }

    if (_ownerOf[id] != address(0)) {
      revert AlreadyExists();
    }

    _deliverNFT(to, id);

    emit Transfer(address(0), to, id);
  }

  function _burnNFT(address from) internal virtual {
    if (from == address(0)) {
      revert InvalidSender();
    }

    // Indiscriminantly burn last NFT in list of owned NFTs for `from`
    uint256 id = _owned[from][_owned[from].length - 1];
    _owned[from].pop();
    delete _ownedIndex[id];
    delete _ownerOf[id];
    delete getApproved[id];

    availableIds.push(id);

    emit Transfer(from, address(0), id);
  }

  function _removeSpecificNFT(address from, uint256 id) private {
    uint256 lastId;
    if (_isContract(from)) {
      lastId = _contractOwned[from][_contractOwned[from].length - 1];
      _contractOwned[from][_ownedIndex[id]] = lastId;
      _contractOwned[from].pop();
    } else {
      lastId = _owned[from][_owned[from].length - 1];
      _owned[from][_ownedIndex[id]] = lastId;
      _owned[from].pop();
    }
    _ownedIndex[lastId] = _ownedIndex[id];
    delete getApproved[id];
  }

  function _deliverNFT(address to, uint256 id) private {
    _ownerOf[id] = to;
    if (_isContract(to)) {
      _contractOwned[to].push(id);
      _ownedIndex[id] = _contractOwned[to].length - 1;
    } else {
      _owned[to].push(id);
      _ownedIndex[id] = _owned[to].length - 1;
    }
  }

  function _setNameSymbol(string memory _name, string memory _symbol) internal {
    name = _name;
    symbol = _symbol;
  }

  function _shouldSkip(address a) private view returns (bool) {
    return whitelist[a] || _isContract(a);
  }

  function _isContract(address a) private view returns (bool result) {
    assembly {
      result := extcodesize(a)
    }
  }

  function _beforeTokenTransfer(
    address from,
    address to,
    uint256 amount
  ) internal virtual {}
}

Settings
{
  "evmVersion": "paris",
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"string","name":"_baseTokenURI","type":"string"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_startTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"NotFound","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsafeRecipient","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":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ERC721Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"activePhase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amountOrId","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"availableIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"phase","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"canMintAmountInPhase","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"phase","type":"uint256"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"grantPhaseAccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"phase","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"hasPhaseAccess","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintPerTx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintHasStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"phaseDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"phaseMintsRemaining","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"phases","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"revokeOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"secondsUntilStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxMintPerTx","type":"uint256"}],"name":"setMaxPerTx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"mintActive_","type":"bool"}],"name":"setMintActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startTime","type":"uint256"}],"name":"setStartTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAvailableIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"totalNFTsOwned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalNativeSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

60e06040523480156200001157600080fd5b50604051620062a1380380620062a183398181016040528101906200003791906200053f565b868686868580600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a4576040517f49e27cff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a350846001908162000151919062000890565b50836002908162000163919062000890565b508260ff1660808160ff16815250508160c08181525050608051600a6200018b919062000afa565b8262000198919062000b4b565b60a0818152505050505050506000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001600c60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555068056bc75e2d6310000060118190555083600f819055506000601560016101000a81548160ff0219169083151502179055506103e8601081905550806016819055506000601560006101000a81548160ff02191690831515021790555082600e9081620002af919062000890565b50610e1060148190555060026013819055505050505050505062000b96565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200033782620002ec565b810181811067ffffffffffffffff82111715620003595762000358620002fd565b5b80604052505050565b60006200036e620002ce565b90506200037c82826200032c565b919050565b600067ffffffffffffffff8211156200039f576200039e620002fd565b5b620003aa82620002ec565b9050602081019050919050565b60005b83811015620003d7578082015181840152602081019050620003ba565b60008484015250505050565b6000620003fa620003f48462000381565b62000362565b905082815260208101848484011115620004195762000418620002e7565b5b62000426848285620003b7565b509392505050565b600082601f830112620004465762000445620002e2565b5b815162000458848260208601620003e3565b91505092915050565b600060ff82169050919050565b620004798162000461565b81146200048557600080fd5b50565b60008151905062000499816200046e565b92915050565b6000819050919050565b620004b4816200049f565b8114620004c057600080fd5b50565b600081519050620004d481620004a9565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200050782620004da565b9050919050565b6200051981620004fa565b81146200052557600080fd5b50565b60008151905062000539816200050e565b92915050565b600080600080600080600060e0888a031215620005615762000560620002d8565b5b600088015167ffffffffffffffff811115620005825762000581620002dd565b5b620005908a828b016200042e565b975050602088015167ffffffffffffffff811115620005b457620005b3620002dd565b5b620005c28a828b016200042e565b9650506040620005d58a828b0162000488565b9550506060620005e88a828b01620004c3565b945050608088015167ffffffffffffffff8111156200060c576200060b620002dd565b5b6200061a8a828b016200042e565b93505060a06200062d8a828b0162000528565b92505060c0620006408a828b01620004c3565b91505092959891949750929550565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620006a257607f821691505b602082108103620006b857620006b76200065a565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620007227fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620006e3565b6200072e8683620006e3565b95508019841693508086168417925050509392505050565b6000819050919050565b6000620007716200076b62000765846200049f565b62000746565b6200049f565b9050919050565b6000819050919050565b6200078d8362000750565b620007a56200079c8262000778565b848454620006f0565b825550505050565b600090565b620007bc620007ad565b620007c981848462000782565b505050565b5b81811015620007f157620007e5600082620007b2565b600181019050620007cf565b5050565b601f82111562000840576200080a81620006be565b6200081584620006d3565b8101602085101562000825578190505b6200083d6200083485620006d3565b830182620007ce565b50505b505050565b600082821c905092915050565b6000620008656000198460080262000845565b1980831691505092915050565b600062000880838362000852565b9150826002028217905092915050565b6200089b826200064f565b67ffffffffffffffff811115620008b757620008b6620002fd565b5b620008c3825462000689565b620008d0828285620007f5565b600060209050601f831160018114620009085760008415620008f3578287015190505b620008ff858262000872565b8655506200096f565b601f1984166200091886620006be565b60005b8281101562000942578489015182556001820191506020850194506020810190506200091b565b868310156200096257848901516200095e601f89168262000852565b8355505b6001600288020188555050505b505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008160011c9050919050565b6000808291508390505b600185111562000a0557808604811115620009dd57620009dc62000977565b5b6001851615620009ed5780820291505b8081029050620009fd85620009a6565b9450620009bd565b94509492505050565b60008262000a20576001905062000af3565b8162000a30576000905062000af3565b816001811462000a49576002811462000a545762000a8a565b600191505062000af3565b60ff84111562000a695762000a6862000977565b5b8360020a91508482111562000a835762000a8262000977565b5b5062000af3565b5060208310610133831016604e8410600b841016171562000ac45782820a90508381111562000abe5762000abd62000977565b5b62000af3565b62000ad38484846001620009b3565b9250905081840481111562000aed5762000aec62000977565b5b81810290505b9392505050565b600062000b07826200049f565b915062000b148362000461565b925062000b437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848462000a0e565b905092915050565b600062000b58826200049f565b915062000b65836200049f565b925082820262000b75816200049f565b9150828204841483151762000b8f5762000b8e62000977565b5b5092915050565b60805160a05160c0516156c662000bdb60003960008181611ac301526136e80152600081816112f501526132750152600081816115f7015261333a01526156c66000f3fe6080604052600436106102e45760003560e01c806381456f4811610190578063b76b8ced116100dc578063d9adc19111610095578063e985e9c51161006f578063e985e9c514610b91578063ee1cc94414610bce578063f2fde38b14610bf7578063ff6728ad14610c20576102e4565b8063d9adc19114610aec578063dd62ed3e14610b29578063de7fcb1d14610b66576102e4565b8063b76b8ced146109ca578063b88d4fde146109f5578063c6f6f21614610a1e578063c87b56dd14610a47578063d528d11814610a84578063d547cfb714610ac1576102e4565b8063a0712d6811610149578063a4fd255911610123578063a4fd2559146108fc578063a9059cbb14610925578063a96fd9d514610962578063ac5553ce1461099f576102e4565b8063a0712d681461088c578063a21b5fe9146108a8578063a22cb465146108d3576102e4565b806381456f481461077a5780638da5cb5b146107a557806391b7f5ed146107d057806395d89b41146107f95780639b19251a14610824578063a035b1fe14610861576102e4565b806325fd90f31161024f5780634f02c420116102085780635c975abb116101e25780635c975abb146106aa5780636352211e146106d557806370a082311461071257806378e979251461074f576102e4565b80634f02c4201461062d57806353d6fd591461065857806355f804b314610681576102e4565b806325fd90f3146105455780632b96895814610570578063313ce567146105875780633e0a322d146105b257806342842e0e146105db578063484b973c14610604576102e4565b80630ca793c3116102a15780630ca793c3146104215780630e1b26c61461045e57806316c38b3c1461048957806318160ddd146104b25780632154dc39146104dd57806323b872dd14610508576102e4565b806301ffc9a7146102e957806304bdc76b14610326578063051cbd241461035157806306fdde031461037c578063081812fc146103a7578063095ea7b3146103e4575b600080fd5b3480156102f557600080fd5b50610310600480360381019061030b9190613ffd565b610c5d565b60405161031d9190614045565b60405180910390f35b34801561033257600080fd5b5061033b610d8e565b6040516103489190614079565b60405180910390f35b34801561035d57600080fd5b50610366610d9b565b6040516103739190614079565b60405180910390f35b34801561038857600080fd5b50610391610dc6565b60405161039e9190614124565b60405180910390f35b3480156103b357600080fd5b506103ce60048036038101906103c99190614172565b610e54565b6040516103db91906141e0565b60405180910390f35b3480156103f057600080fd5b5061040b60048036038101906104069190614227565b610e87565b6040516104189190614045565b60405180910390f35b34801561042d57600080fd5b5061044860048036038101906104439190614267565b611180565b6040516104559190614045565b60405180910390f35b34801561046a57600080fd5b506104736111df565b6040516104809190614079565b60405180910390f35b34801561049557600080fd5b506104b060048036038101906104ab91906142e6565b611251565b005b3480156104be57600080fd5b506104c76112f3565b6040516104d49190614079565b60405180910390f35b3480156104e957600080fd5b506104f2611317565b6040516104ff9190614079565b60405180910390f35b34801561051457600080fd5b5061052f600480360381019061052a9190614313565b61131d565b60405161053c9190614045565b60405180910390f35b34801561055157600080fd5b5061055a6114ae565b6040516105679190614045565b60405180910390f35b34801561057c57600080fd5b506105856114d2565b005b34801561059357600080fd5b5061059c6115f5565b6040516105a99190614382565b60405180910390f35b3480156105be57600080fd5b506105d960048036038101906105d49190614172565b611619565b005b3480156105e757600080fd5b5061060260048036038101906105fd9190614313565b6116a8565b005b34801561061057600080fd5b5061062b60048036038101906106269190614227565b6117dc565b005b34801561063957600080fd5b5061064261186f565b60405161064f9190614079565b60405180910390f35b34801561066457600080fd5b5061067f600480360381019061067a919061439d565b611875565b005b34801561068d57600080fd5b506106a860048036038101906106a39190614512565b611955565b005b3480156106b657600080fd5b506106bf6119ed565b6040516106cc9190614045565b60405180910390f35b3480156106e157600080fd5b506106fc60048036038101906106f79190614172565b611a00565b60405161070991906141e0565b60405180910390f35b34801561071e57600080fd5b506107396004803603810190610734919061455b565b611aa3565b6040516107469190614079565b60405180910390f35b34801561075b57600080fd5b50610764611abb565b6040516107719190614079565b60405180910390f35b34801561078657600080fd5b5061078f611ac1565b60405161079c9190614079565b60405180910390f35b3480156107b157600080fd5b506107ba611ae5565b6040516107c791906141e0565b60405180910390f35b3480156107dc57600080fd5b506107f760048036038101906107f29190614172565b611b09565b005b34801561080557600080fd5b5061080e611b98565b60405161081b9190614124565b60405180910390f35b34801561083057600080fd5b5061084b6004803603810190610846919061455b565b611c26565b6040516108589190614045565b60405180910390f35b34801561086d57600080fd5b50610876611c46565b6040516108839190614079565b60405180910390f35b6108a660048036038101906108a19190614172565b611c4c565b005b3480156108b457600080fd5b506108bd611f21565b6040516108ca9190614045565b60405180910390f35b3480156108df57600080fd5b506108fa60048036038101906108f5919061439d565b611f2e565b005b34801561090857600080fd5b50610923600480360381019061091e9190614650565b61202b565b005b34801561093157600080fd5b5061094c60048036038101906109479190614227565b612156565b6040516109599190614045565b60405180910390f35b34801561096e57600080fd5b50610989600480360381019061098491906146bf565b61216b565b6040516109969190614045565b60405180910390f35b3480156109ab57600080fd5b506109b46121c8565b6040516109c19190614079565b60405180910390f35b3480156109d657600080fd5b506109df6121ce565b6040516109ec9190614079565b60405180910390f35b348015610a0157600080fd5b50610a1c6004803603810190610a17919061475a565b6121d4565b005b348015610a2a57600080fd5b50610a456004803603810190610a409190614172565b61230e565b005b348015610a5357600080fd5b50610a6e6004803603810190610a699190614172565b61239d565b604051610a7b9190614124565b60405180910390f35b348015610a9057600080fd5b50610aab6004803603810190610aa69190614172565b6123d1565b604051610ab89190614079565b60405180910390f35b348015610acd57600080fd5b50610ad66123f5565b604051610ae39190614124565b60405180910390f35b348015610af857600080fd5b50610b136004803603810190610b0e919061455b565b612483565b604051610b209190614079565b60405180910390f35b348015610b3557600080fd5b50610b506004803603810190610b4b91906147e2565b6124cf565b604051610b5d9190614079565b60405180910390f35b348015610b7257600080fd5b50610b7b6124f4565b604051610b889190614079565b60405180910390f35b348015610b9d57600080fd5b50610bb86004803603810190610bb391906147e2565b6124fa565b604051610bc59190614045565b60405180910390f35b348015610bda57600080fd5b50610bf56004803603810190610bf091906142e6565b612529565b005b348015610c0357600080fd5b50610c1e6004803603810190610c19919061455b565b6125cb565b005b348015610c2c57600080fd5b50610c476004803603810190610c4291906146bf565b612753565b604051610c549190614079565b60405180910390f35b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610d2857507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610d775750632a55205a60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610d875750610d8682612778565b5b9050919050565b6000600d80549050905090565b6000610da5611f21565b610dbe5742601654610db79190614851565b9050610dc3565b600090505b90565b60018054610dd3906148b4565b80601f0160208091040260200160405190810160405280929190818152602001828054610dff906148b4565b8015610e4c5780601f10610e2157610100808354040283529160200191610e4c565b820191906000526020600020905b815481529060010190602001808311610e2f57829003601f168201915b505050505081565b60066020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006003548211158015610e9b5750600082115b1561108f5760006008600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610f9b5750600760008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b15610fd2576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836006600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040516110819190614079565b60405180910390a350611176565b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161116d9190614079565b60405180910390a35b6001905092915050565b6000816012600086815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101590509392505050565b60006111e9611f21565b6111f6576000905061124e565b6000601654426112069190614851565b9050600060016014548361121a9190614914565b6112249190614945565b905060135481111561124857600160135461123f9190614945565b9250505061124e565b80925050505b90565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146112d6576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80601560006101000a81548160ff02191690831515021790555050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600f5481565b600080600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156113e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113d9906149c5565b60405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114965782816114159190614851565b600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6114a18585856127e2565b5060019150509392505050565b6000601560019054906101000a900460ff16806114cd57506016544210155b905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611557576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461169e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060168190555050565b6116b433848484612bd0565b60008273ffffffffffffffffffffffffffffffffffffffff163b141580156117a0575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168273ffffffffffffffffffffffffffffffffffffffff1663150b7a023386856040518463ffffffff1660e01b815260040161173b93929190614a1c565b6020604051808303816000875af115801561175a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177e9190614a7b565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b156117d7576040517f3da6393100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611861576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61186b8282612fda565b5050565b60035481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146118fa576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600c60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119da576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600e90816119e99190614c54565b5050565b601560009054906101000a900460ff1681565b60006008600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611a9e576040517fc5723b5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60046020528060005260406000206000915090505481565b60165481565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b8e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060118190555050565b60028054611ba5906148b4565b80601f0160208091040260200160405190810160405280929190818152602001828054611bd1906148b4565b8015611c1e5780601f10611bf357610100808354040283529160200191611c1e565b820191906000526020600020905b815481529060010190602001808311611c0157829003601f168201915b505050505081565b600c6020528060005260406000206000915054906101000a900460ff1681565b60115481565b611c546114ae565b611c93576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8a90614d72565b60405180910390fd5b601560009054906101000a900460ff1615611cad57600080fd5b601054811115611cf2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ce990614dde565b60405180910390fd5b600f5481600354611d039190614945565b1115611d44576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d3b90614e4a565b60405180910390fd5b60115481611d529190614e6a565b341015611d94576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d8b90614ef8565b60405180910390fd5b6000600190505b6013548111611ea25780611dad6111df565b03611e8f57611dbd813384611180565b611dc68261306e565b604051602001611dd69190614fa0565b60405160208183030381529060405290611e26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e1d9190614124565b60405180910390fd5b50816012600083815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611e879190614851565b925050819055505b8080611e9a90614fd5565b915050611d9b565b506000341115611f145760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015611f12573d6000803e3d6000fd5b505b611f1e3382612fda565b50565b6000601654421015905090565b80600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405161201f9190614045565b60405180910390a35050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146120b0576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b825181101561215057816012600086815260200190815260200160002060008584815181106120e5576120e461501d565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546121369190614945565b92505081905550808061214890614fd5565b9150506120b3565b50505050565b60006121633384846127e2565b905092915050565b6000806012600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411905092915050565b60145481565b60135481565b6121e033868686612bd0565b60008473ffffffffffffffffffffffffffffffffffffffff163b141580156122d0575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168473ffffffffffffffffffffffffffffffffffffffff1663150b7a0233888787876040518663ffffffff1660e01b815260040161226b959493929190615079565b6020604051808303816000875af115801561228a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ae9190614a7b565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b15612307576040517f3da6393100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612393576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060108190555050565b6060600e6123aa8361306e565b6040516020016123bb929190615170565b6040516020818303038152906040529050919050565b600d81815481106123e157600080fd5b906000526020600020016000915090505481565b600e8054612402906148b4565b80601f016020809104026020016040519081016040528092919081815260200182805461242e906148b4565b801561247b5780601f106124505761010080835404028352916020019161247b565b820191906000526020600020905b81548152906001019060200180831161245e57829003601f168201915b505050505081565b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b6005602052816000526040600020602052806000526040600020600091509150505481565b60105481565b60076020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146125ae576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80601560016101000a81548160ff02191690831515021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612650576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036126b6576040517f49e27cff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a350565b6012602052816000526040600020602052806000526040600020600091509150505481565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60006127ef84848461313c565b60006127f9613336565b90506000600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905061288c8761336a565b1561293357600083600a60008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506128e19190614e6a565b836128ec9190614851565b905085811015612931576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612928906151ef565b60405180910390fd5b505b84600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546129829190614851565b9250508190555084600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055506129df87613375565b1580612a2d57506000600960008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050115b15612ac157600083600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612a7f9190614914565b8484612a8b9190614914565b612a959190614851565b905060005b81811015612abe57612aab896133db565b8080612ab690614fd5565b915050612a9a565b50505b612aca86613375565b612b5d5760008382612adc9190614914565b84600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612b279190614914565b612b319190614851565b905060005b81811015612b5a57612b4788613660565b8080612b5290614fd5565b915050612b36565b50505b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e03148787604051612bba9190614079565b60405180910390a3600193505050509392505050565b6008600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614612c71576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c689061525b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612ce0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cd7906152c7565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480612da05750600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b80612e0957506006600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b612e48576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e3f90615333565b60405180910390fd5b612e50613336565b600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612e9e9190614851565b92505081905550612ead613336565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550612f0383826138b3565b612f0d8282613c37565b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a48173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e031487612fbf613336565b604051612fcc9190614079565b60405180910390a350505050565b612fe2613336565b81612fed9190614e6a565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461303b9190614945565b9250508190555060005b818110156130695761305683613660565b808061306190614fd5565b915050613045565b505050565b60606000600161307d84613e39565b01905060008167ffffffffffffffff81111561309c5761309b6143e7565b5b6040519080825280601f01601f1916602001820160405280156130ce5781602001600182028036833780820191505090505b509050600082602001820190505b600115613131578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581613125576131246148e5565b5b049450600085036130dc575b819350505050919050565b613147838383613f8c565b6013546131526111df565b116132405760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614806131fc575060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b61323b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613232906153c5565b60405180910390fd5b613331565b60b46014546013546132529190614e6a565b60165461325f9190614945565b6132699190614945565b421015613330576103e87f000000000000000000000000000000000000000000000000000000000000000060056132a09190614e6a565b6132aa9190614914565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561332b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161332290615431565b60405180910390fd5b613331565b5b505050565b60007f0000000000000000000000000000000000000000000000000000000000000000600a6133659190615584565b905090565b6000813b9050919050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16806133d457506133d38261336a565b5b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603613441576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506134d19190614851565b815481106134e2576134e161501d565b5b90600052602060002001549050600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548061353e5761353d6155cf565b5b60019003818190600052602060002001600090559055600b6000828152602001908152602001600020600090556008600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556006600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600d81908060018154018082558091505060019003906000526020600020016000909190919091505580600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036136c6576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080600d8054905003613755576003600081548092919060010191905055507f0000000000000000000000000000000000000000000000000000000000000000600354111561374b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161374290615670565b60405180910390fd5b60035490506137b0565b600d6001600d805490506137699190614851565b8154811061377a5761377961501d565b5b90600052602060002001549050600d805480613799576137986155cf565b5b600190038181906000526020600020016000905590555b600073ffffffffffffffffffffffffffffffffffffffff166008600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613849576040517f23369fa600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6138538282613c37565b808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050565b60006138be8361336a565b15613a4c57600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600a60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506139519190614851565b815481106139625761396161501d565b5b9060005260206000200154905080600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600b600085815260200190815260200160002054815481106139d4576139d361501d565b5b9060005260206000200181905550600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480613a3157613a306155cf565b5b60019003818190600052602060002001600090559055613bd1565b600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600960008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050613ada9190614851565b81548110613aeb57613aea61501d565b5b9060005260206000200154905080600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600b60008581526020019081526020016000205481548110613b5d57613b5c61501d565b5b9060005260206000200181905550600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480613bba57613bb96155cf565b5b600190038181906000526020600020016000905590555b600b600083815260200190815260200160002054600b6000838152602001908152602001600020819055506006600083815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505050565b816008600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613c928261336a565b15613d6857600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002001600090919091909150556001600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050613d4c9190614851565b600b600083815260200190815260200160002081905550613e35565b600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002001600090919091909150556001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050613e1d9190614851565b600b6000838152602001908152602001600020819055505b5050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613e97577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381613e8d57613e8c6148e5565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310613ed4576d04ee2d6d415b85acef81000000008381613eca57613ec96148e5565b5b0492506020810190505b662386f26fc100008310613f0357662386f26fc100008381613ef957613ef86148e5565b5b0492506010810190505b6305f5e1008310613f2c576305f5e1008381613f2257613f216148e5565b5b0492506008810190505b6127108310613f51576127108381613f4757613f466148e5565b5b0492506004810190505b60648310613f745760648381613f6a57613f696148e5565b5b0492506002810190505b600a8310613f83576001810190505b80915050919050565b505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613fda81613fa5565b8114613fe557600080fd5b50565b600081359050613ff781613fd1565b92915050565b60006020828403121561401357614012613f9b565b5b600061402184828501613fe8565b91505092915050565b60008115159050919050565b61403f8161402a565b82525050565b600060208201905061405a6000830184614036565b92915050565b6000819050919050565b61407381614060565b82525050565b600060208201905061408e600083018461406a565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156140ce5780820151818401526020810190506140b3565b60008484015250505050565b6000601f19601f8301169050919050565b60006140f682614094565b614100818561409f565b93506141108185602086016140b0565b614119816140da565b840191505092915050565b6000602082019050818103600083015261413e81846140eb565b905092915050565b61414f81614060565b811461415a57600080fd5b50565b60008135905061416c81614146565b92915050565b60006020828403121561418857614187613f9b565b5b60006141968482850161415d565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006141ca8261419f565b9050919050565b6141da816141bf565b82525050565b60006020820190506141f560008301846141d1565b92915050565b614204816141bf565b811461420f57600080fd5b50565b600081359050614221816141fb565b92915050565b6000806040838503121561423e5761423d613f9b565b5b600061424c85828601614212565b925050602061425d8582860161415d565b9150509250929050565b6000806000606084860312156142805761427f613f9b565b5b600061428e8682870161415d565b935050602061429f86828701614212565b92505060406142b08682870161415d565b9150509250925092565b6142c38161402a565b81146142ce57600080fd5b50565b6000813590506142e0816142ba565b92915050565b6000602082840312156142fc576142fb613f9b565b5b600061430a848285016142d1565b91505092915050565b60008060006060848603121561432c5761432b613f9b565b5b600061433a86828701614212565b935050602061434b86828701614212565b925050604061435c8682870161415d565b9150509250925092565b600060ff82169050919050565b61437c81614366565b82525050565b60006020820190506143976000830184614373565b92915050565b600080604083850312156143b4576143b3613f9b565b5b60006143c285828601614212565b92505060206143d3858286016142d1565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61441f826140da565b810181811067ffffffffffffffff8211171561443e5761443d6143e7565b5b80604052505050565b6000614451613f91565b905061445d8282614416565b919050565b600067ffffffffffffffff82111561447d5761447c6143e7565b5b614486826140da565b9050602081019050919050565b82818337600083830152505050565b60006144b56144b084614462565b614447565b9050828152602081018484840111156144d1576144d06143e2565b5b6144dc848285614493565b509392505050565b600082601f8301126144f9576144f86143dd565b5b81356145098482602086016144a2565b91505092915050565b60006020828403121561452857614527613f9b565b5b600082013567ffffffffffffffff81111561454657614545613fa0565b5b614552848285016144e4565b91505092915050565b60006020828403121561457157614570613f9b565b5b600061457f84828501614212565b91505092915050565b600067ffffffffffffffff8211156145a3576145a26143e7565b5b602082029050602081019050919050565b600080fd5b60006145cc6145c784614588565b614447565b905080838252602082019050602084028301858111156145ef576145ee6145b4565b5b835b8181101561461857806146048882614212565b8452602084019350506020810190506145f1565b5050509392505050565b600082601f830112614637576146366143dd565b5b81356146478482602086016145b9565b91505092915050565b60008060006060848603121561466957614668613f9b565b5b60006146778682870161415d565b935050602084013567ffffffffffffffff81111561469857614697613fa0565b5b6146a486828701614622565b92505060406146b58682870161415d565b9150509250925092565b600080604083850312156146d6576146d5613f9b565b5b60006146e48582860161415d565b92505060206146f585828601614212565b9150509250929050565b600080fd5b60008083601f84011261471a576147196143dd565b5b8235905067ffffffffffffffff811115614737576147366146ff565b5b602083019150836001820283011115614753576147526145b4565b5b9250929050565b60008060008060006080868803121561477657614775613f9b565b5b600061478488828901614212565b955050602061479588828901614212565b94505060406147a68882890161415d565b935050606086013567ffffffffffffffff8111156147c7576147c6613fa0565b5b6147d388828901614704565b92509250509295509295909350565b600080604083850312156147f9576147f8613f9b565b5b600061480785828601614212565b925050602061481885828601614212565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061485c82614060565b915061486783614060565b925082820390508181111561487f5761487e614822565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806148cc57607f821691505b6020821081036148df576148de614885565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061491f82614060565b915061492a83614060565b92508261493a576149396148e5565b5b828204905092915050565b600061495082614060565b915061495b83614060565b925082820190508082111561497357614972614822565b5b92915050565b7f4e6f7420656e6f75676820616c6c6f77616e63652e0000000000000000000000600082015250565b60006149af60158361409f565b91506149ba82614979565b602082019050919050565b600060208201905081810360008301526149de816149a2565b9050919050565b600082825260208201905092915050565b50565b6000614a066000836149e5565b9150614a11826149f6565b600082019050919050565b6000608082019050614a3160008301866141d1565b614a3e60208301856141d1565b614a4b604083018461406a565b8181036060830152614a5c816149f9565b9050949350505050565b600081519050614a7581613fd1565b92915050565b600060208284031215614a9157614a90613f9b565b5b6000614a9f84828501614a66565b91505092915050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302614b0a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614acd565b614b148683614acd565b95508019841693508086168417925050509392505050565b6000819050919050565b6000614b51614b4c614b4784614060565b614b2c565b614060565b9050919050565b6000819050919050565b614b6b83614b36565b614b7f614b7782614b58565b848454614ada565b825550505050565b600090565b614b94614b87565b614b9f818484614b62565b505050565b5b81811015614bc357614bb8600082614b8c565b600181019050614ba5565b5050565b601f821115614c0857614bd981614aa8565b614be284614abd565b81016020851015614bf1578190505b614c05614bfd85614abd565b830182614ba4565b50505b505050565b600082821c905092915050565b6000614c2b60001984600802614c0d565b1980831691505092915050565b6000614c448383614c1a565b9150826002028217905092915050565b614c5d82614094565b67ffffffffffffffff811115614c7657614c756143e7565b5b614c8082546148b4565b614c8b828285614bc7565b600060209050601f831160018114614cbe5760008415614cac578287015190505b614cb68582614c38565b865550614d1e565b601f198416614ccc86614aa8565b60005b82811015614cf457848901518255600182019150602085019450602081019050614ccf565b86831015614d115784890151614d0d601f891682614c1a565b8355505b6001600288020188555050505b505050505050565b7f4d696e74696e67206973206e6f74206163746976652e00000000000000000000600082015250565b6000614d5c60168361409f565b9150614d6782614d26565b602082019050919050565b60006020820190508181036000830152614d8b81614d4f565b9050919050565b7f43616e6e6f74206d696e742074686174206d616e79206174206f6e63652e0000600082015250565b6000614dc8601e8361409f565b9150614dd382614d92565b602082019050919050565b60006020820190508181036000830152614df781614dbb565b9050919050565b7f46696e6973686564206d696e74696e672e000000000000000000000000000000600082015250565b6000614e3460118361409f565b9150614e3f82614dfe565b602082019050919050565b60006020820190508181036000830152614e6381614e27565b9050919050565b6000614e7582614060565b9150614e8083614060565b9250828202614e8e81614060565b91508282048414831517614ea557614ea4614822565b5b5092915050565b7f4e6f7420656e6f7567682046544d2073656e742e000000000000000000000000600082015250565b6000614ee260148361409f565b9150614eed82614eac565b602082019050919050565b60006020820190508181036000830152614f1181614ed5565b9050919050565b7f43757272656e746c7920696e2070686173652000000000000000000000000000815250565b600081905092915050565b6000614f5482614094565b614f5e8185614f3e565b9350614f6e8185602086016140b0565b80840191505092915050565b7f2e00000000000000000000000000000000000000000000000000000000000000815250565b6000614fab82614f18565b601382019150614fbb8284614f49565b9150614fc682614f7a565b60018201915081905092915050565b6000614fe082614060565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361501257615011614822565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061505883856149e5565b9350615065838584614493565b61506e836140da565b840190509392505050565b600060808201905061508e60008301886141d1565b61509b60208301876141d1565b6150a8604083018661406a565b81810360608301526150bb81848661504c565b90509695505050505050565b600081546150d4816148b4565b6150de8186614f3e565b945060018216600081146150f9576001811461510e57615141565b60ff1983168652811515820286019350615141565b61511785614aa8565b60005b838110156151395781548189015260018201915060208101905061511a565b838801955050505b50505092915050565b7f2e6a736f6e000000000000000000000000000000000000000000000000000000815250565b600061517c82856150c7565b91506151888284614f49565b91506151938261514a565b6005820191508190509392505050565b7f4e6f7420656e6f75676820746f6b656e2062616c616e63652e00000000000000600082015250565b60006151d960198361409f565b91506151e4826151a3565b602082019050919050565b60006020820190508181036000830152615208816151cc565b9050919050565b7f53656e646572206973206e6f74206f776e6572206f66204e46542e0000000000600082015250565b6000615245601b8361409f565b91506152508261520f565b602082019050919050565b6000602082019050818103600083015261527481615238565b9050919050565b7f43616e6e6f742073656e6420746f206e756c6c20616464726573732e00000000600082015250565b60006152b1601c8361409f565b91506152bc8261527b565b602082019050919050565b600060208201905081810360008301526152e0816152a4565b9050919050565b7f4f70657261746f72206973206e6f7420617070726f7665642e00000000000000600082015250565b600061531d60198361409f565b9150615328826152e7565b602082019050919050565b6000602082019050818103600083015261534c81615310565b9050919050565b7f43616e6e6f74207472616e7366657220756e74696c206d696e7420656e74657260008201527f73207075626c69632e0000000000000000000000000000000000000000000000602082015250565b60006153af60298361409f565b91506153ba82615353565b604082019050919050565b600060208201905081810360008301526153de816153a2565b9050919050565b7f4e6f206d6f7265207468616e20302e352520617420746869732073746167652e600082015250565b600061541b60208361409f565b9150615426826153e5565b602082019050919050565b6000602082019050818103600083015261544a8161540e565b9050919050565b60008160011c9050919050565b6000808291508390505b60018511156154a85780860481111561548457615483614822565b5b60018516156154935780820291505b80810290506154a185615451565b9450615468565b94509492505050565b6000826154c1576001905061557d565b816154cf576000905061557d565b81600181146154e557600281146154ef5761551e565b600191505061557d565b60ff84111561550157615500614822565b5b8360020a91508482111561551857615517614822565b5b5061557d565b5060208310610133831016604e8410600b84101617156155535782820a90508381111561554e5761554d614822565b5b61557d565b615560848484600161545e565b9250905081840481111561557757615576614822565b5b81810290505b9392505050565b600061558f82614060565b915061559a83614366565b92506155c77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84846154b1565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f43616e6e6f74206d696e74206d6f7265207468616e20676976656e207375707060008201527f6c792e0000000000000000000000000000000000000000000000000000000000602082015250565b600061565a60238361409f565b9150615665826155fe565b604082019050919050565b600060208201905081810360008301526156898161564d565b905091905056fea26469706673582212206593f69164f97361fef760970602d8233d62eb5e1907650df55805aa77e5528464736f6c6343000814003300000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000001600000000000000000000000004a8ddd9b108f5ba439a7b461b6036c20f0737342000000000000000000000000000000000000000000000000000000006761f2d10000000000000000000000000000000000000000000000000000000000000004486177670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044841574700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004468747470733a2f2f697066732e696f2f697066732f516d665a72374471553563566e74386431486874743543756a44323578613875424665396b713374527a617056422f00000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106102e45760003560e01c806381456f4811610190578063b76b8ced116100dc578063d9adc19111610095578063e985e9c51161006f578063e985e9c514610b91578063ee1cc94414610bce578063f2fde38b14610bf7578063ff6728ad14610c20576102e4565b8063d9adc19114610aec578063dd62ed3e14610b29578063de7fcb1d14610b66576102e4565b8063b76b8ced146109ca578063b88d4fde146109f5578063c6f6f21614610a1e578063c87b56dd14610a47578063d528d11814610a84578063d547cfb714610ac1576102e4565b8063a0712d6811610149578063a4fd255911610123578063a4fd2559146108fc578063a9059cbb14610925578063a96fd9d514610962578063ac5553ce1461099f576102e4565b8063a0712d681461088c578063a21b5fe9146108a8578063a22cb465146108d3576102e4565b806381456f481461077a5780638da5cb5b146107a557806391b7f5ed146107d057806395d89b41146107f95780639b19251a14610824578063a035b1fe14610861576102e4565b806325fd90f31161024f5780634f02c420116102085780635c975abb116101e25780635c975abb146106aa5780636352211e146106d557806370a082311461071257806378e979251461074f576102e4565b80634f02c4201461062d57806353d6fd591461065857806355f804b314610681576102e4565b806325fd90f3146105455780632b96895814610570578063313ce567146105875780633e0a322d146105b257806342842e0e146105db578063484b973c14610604576102e4565b80630ca793c3116102a15780630ca793c3146104215780630e1b26c61461045e57806316c38b3c1461048957806318160ddd146104b25780632154dc39146104dd57806323b872dd14610508576102e4565b806301ffc9a7146102e957806304bdc76b14610326578063051cbd241461035157806306fdde031461037c578063081812fc146103a7578063095ea7b3146103e4575b600080fd5b3480156102f557600080fd5b50610310600480360381019061030b9190613ffd565b610c5d565b60405161031d9190614045565b60405180910390f35b34801561033257600080fd5b5061033b610d8e565b6040516103489190614079565b60405180910390f35b34801561035d57600080fd5b50610366610d9b565b6040516103739190614079565b60405180910390f35b34801561038857600080fd5b50610391610dc6565b60405161039e9190614124565b60405180910390f35b3480156103b357600080fd5b506103ce60048036038101906103c99190614172565b610e54565b6040516103db91906141e0565b60405180910390f35b3480156103f057600080fd5b5061040b60048036038101906104069190614227565b610e87565b6040516104189190614045565b60405180910390f35b34801561042d57600080fd5b5061044860048036038101906104439190614267565b611180565b6040516104559190614045565b60405180910390f35b34801561046a57600080fd5b506104736111df565b6040516104809190614079565b60405180910390f35b34801561049557600080fd5b506104b060048036038101906104ab91906142e6565b611251565b005b3480156104be57600080fd5b506104c76112f3565b6040516104d49190614079565b60405180910390f35b3480156104e957600080fd5b506104f2611317565b6040516104ff9190614079565b60405180910390f35b34801561051457600080fd5b5061052f600480360381019061052a9190614313565b61131d565b60405161053c9190614045565b60405180910390f35b34801561055157600080fd5b5061055a6114ae565b6040516105679190614045565b60405180910390f35b34801561057c57600080fd5b506105856114d2565b005b34801561059357600080fd5b5061059c6115f5565b6040516105a99190614382565b60405180910390f35b3480156105be57600080fd5b506105d960048036038101906105d49190614172565b611619565b005b3480156105e757600080fd5b5061060260048036038101906105fd9190614313565b6116a8565b005b34801561061057600080fd5b5061062b60048036038101906106269190614227565b6117dc565b005b34801561063957600080fd5b5061064261186f565b60405161064f9190614079565b60405180910390f35b34801561066457600080fd5b5061067f600480360381019061067a919061439d565b611875565b005b34801561068d57600080fd5b506106a860048036038101906106a39190614512565b611955565b005b3480156106b657600080fd5b506106bf6119ed565b6040516106cc9190614045565b60405180910390f35b3480156106e157600080fd5b506106fc60048036038101906106f79190614172565b611a00565b60405161070991906141e0565b60405180910390f35b34801561071e57600080fd5b506107396004803603810190610734919061455b565b611aa3565b6040516107469190614079565b60405180910390f35b34801561075b57600080fd5b50610764611abb565b6040516107719190614079565b60405180910390f35b34801561078657600080fd5b5061078f611ac1565b60405161079c9190614079565b60405180910390f35b3480156107b157600080fd5b506107ba611ae5565b6040516107c791906141e0565b60405180910390f35b3480156107dc57600080fd5b506107f760048036038101906107f29190614172565b611b09565b005b34801561080557600080fd5b5061080e611b98565b60405161081b9190614124565b60405180910390f35b34801561083057600080fd5b5061084b6004803603810190610846919061455b565b611c26565b6040516108589190614045565b60405180910390f35b34801561086d57600080fd5b50610876611c46565b6040516108839190614079565b60405180910390f35b6108a660048036038101906108a19190614172565b611c4c565b005b3480156108b457600080fd5b506108bd611f21565b6040516108ca9190614045565b60405180910390f35b3480156108df57600080fd5b506108fa60048036038101906108f5919061439d565b611f2e565b005b34801561090857600080fd5b50610923600480360381019061091e9190614650565b61202b565b005b34801561093157600080fd5b5061094c60048036038101906109479190614227565b612156565b6040516109599190614045565b60405180910390f35b34801561096e57600080fd5b50610989600480360381019061098491906146bf565b61216b565b6040516109969190614045565b60405180910390f35b3480156109ab57600080fd5b506109b46121c8565b6040516109c19190614079565b60405180910390f35b3480156109d657600080fd5b506109df6121ce565b6040516109ec9190614079565b60405180910390f35b348015610a0157600080fd5b50610a1c6004803603810190610a17919061475a565b6121d4565b005b348015610a2a57600080fd5b50610a456004803603810190610a409190614172565b61230e565b005b348015610a5357600080fd5b50610a6e6004803603810190610a699190614172565b61239d565b604051610a7b9190614124565b60405180910390f35b348015610a9057600080fd5b50610aab6004803603810190610aa69190614172565b6123d1565b604051610ab89190614079565b60405180910390f35b348015610acd57600080fd5b50610ad66123f5565b604051610ae39190614124565b60405180910390f35b348015610af857600080fd5b50610b136004803603810190610b0e919061455b565b612483565b604051610b209190614079565b60405180910390f35b348015610b3557600080fd5b50610b506004803603810190610b4b91906147e2565b6124cf565b604051610b5d9190614079565b60405180910390f35b348015610b7257600080fd5b50610b7b6124f4565b604051610b889190614079565b60405180910390f35b348015610b9d57600080fd5b50610bb86004803603810190610bb391906147e2565b6124fa565b604051610bc59190614045565b60405180910390f35b348015610bda57600080fd5b50610bf56004803603810190610bf091906142e6565b612529565b005b348015610c0357600080fd5b50610c1e6004803603810190610c19919061455b565b6125cb565b005b348015610c2c57600080fd5b50610c476004803603810190610c4291906146bf565b612753565b604051610c549190614079565b60405180910390f35b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610d2857507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610d775750632a55205a60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610d875750610d8682612778565b5b9050919050565b6000600d80549050905090565b6000610da5611f21565b610dbe5742601654610db79190614851565b9050610dc3565b600090505b90565b60018054610dd3906148b4565b80601f0160208091040260200160405190810160405280929190818152602001828054610dff906148b4565b8015610e4c5780601f10610e2157610100808354040283529160200191610e4c565b820191906000526020600020905b815481529060010190602001808311610e2f57829003601f168201915b505050505081565b60066020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006003548211158015610e9b5750600082115b1561108f5760006008600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610f9b5750600760008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b15610fd2576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836006600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040516110819190614079565b60405180910390a350611176565b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161116d9190614079565b60405180910390a35b6001905092915050565b6000816012600086815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101590509392505050565b60006111e9611f21565b6111f6576000905061124e565b6000601654426112069190614851565b9050600060016014548361121a9190614914565b6112249190614945565b905060135481111561124857600160135461123f9190614945565b9250505061124e565b80925050505b90565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146112d6576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80601560006101000a81548160ff02191690831515021790555050565b7f00000000000000000000000000000000000000000000021e19e0c9bab240000081565b600f5481565b600080600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156113e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113d9906149c5565b60405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114965782816114159190614851565b600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6114a18585856127e2565b5060019150509392505050565b6000601560019054906101000a900460ff16806114cd57506016544210155b905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611557576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3565b7f000000000000000000000000000000000000000000000000000000000000001281565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461169e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060168190555050565b6116b433848484612bd0565b60008273ffffffffffffffffffffffffffffffffffffffff163b141580156117a0575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168273ffffffffffffffffffffffffffffffffffffffff1663150b7a023386856040518463ffffffff1660e01b815260040161173b93929190614a1c565b6020604051808303816000875af115801561175a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177e9190614a7b565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b156117d7576040517f3da6393100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611861576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61186b8282612fda565b5050565b60035481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146118fa576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600c60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119da576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600e90816119e99190614c54565b5050565b601560009054906101000a900460ff1681565b60006008600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611a9e576040517fc5723b5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b60046020528060005260406000206000915090505481565b60165481565b7f000000000000000000000000000000000000000000000000000000000000271081565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b8e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060118190555050565b60028054611ba5906148b4565b80601f0160208091040260200160405190810160405280929190818152602001828054611bd1906148b4565b8015611c1e5780601f10611bf357610100808354040283529160200191611c1e565b820191906000526020600020905b815481529060010190602001808311611c0157829003601f168201915b505050505081565b600c6020528060005260406000206000915054906101000a900460ff1681565b60115481565b611c546114ae565b611c93576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8a90614d72565b60405180910390fd5b601560009054906101000a900460ff1615611cad57600080fd5b601054811115611cf2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ce990614dde565b60405180910390fd5b600f5481600354611d039190614945565b1115611d44576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d3b90614e4a565b60405180910390fd5b60115481611d529190614e6a565b341015611d94576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d8b90614ef8565b60405180910390fd5b6000600190505b6013548111611ea25780611dad6111df565b03611e8f57611dbd813384611180565b611dc68261306e565b604051602001611dd69190614fa0565b60405160208183030381529060405290611e26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e1d9190614124565b60405180910390fd5b50816012600083815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611e879190614851565b925050819055505b8080611e9a90614fd5565b915050611d9b565b506000341115611f145760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015611f12573d6000803e3d6000fd5b505b611f1e3382612fda565b50565b6000601654421015905090565b80600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405161201f9190614045565b60405180910390a35050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146120b0576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b825181101561215057816012600086815260200190815260200160002060008584815181106120e5576120e461501d565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546121369190614945565b92505081905550808061214890614fd5565b9150506120b3565b50505050565b60006121633384846127e2565b905092915050565b6000806012600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411905092915050565b60145481565b60135481565b6121e033868686612bd0565b60008473ffffffffffffffffffffffffffffffffffffffff163b141580156122d0575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168473ffffffffffffffffffffffffffffffffffffffff1663150b7a0233888787876040518663ffffffff1660e01b815260040161226b959493929190615079565b6020604051808303816000875af115801561228a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ae9190614a7b565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b15612307576040517f3da6393100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612393576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060108190555050565b6060600e6123aa8361306e565b6040516020016123bb929190615170565b6040516020818303038152906040529050919050565b600d81815481106123e157600080fd5b906000526020600020016000915090505481565b600e8054612402906148b4565b80601f016020809104026020016040519081016040528092919081815260200182805461242e906148b4565b801561247b5780601f106124505761010080835404028352916020019161247b565b820191906000526020600020905b81548152906001019060200180831161245e57829003601f168201915b505050505081565b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b6005602052816000526040600020602052806000526040600020600091509150505481565b60105481565b60076020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146125ae576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80601560016101000a81548160ff02191690831515021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612650576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036126b6576040517f49e27cff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a350565b6012602052816000526040600020602052806000526040600020600091509150505481565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60006127ef84848461313c565b60006127f9613336565b90506000600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905061288c8761336a565b1561293357600083600a60008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506128e19190614e6a565b836128ec9190614851565b905085811015612931576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612928906151ef565b60405180910390fd5b505b84600460008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546129829190614851565b9250508190555084600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055506129df87613375565b1580612a2d57506000600960008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050115b15612ac157600083600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612a7f9190614914565b8484612a8b9190614914565b612a959190614851565b905060005b81811015612abe57612aab896133db565b8080612ab690614fd5565b915050612a9a565b50505b612aca86613375565b612b5d5760008382612adc9190614914565b84600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612b279190614914565b612b319190614851565b905060005b81811015612b5a57612b4788613660565b8080612b5290614fd5565b915050612b36565b50505b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e03148787604051612bba9190614079565b60405180910390a3600193505050509392505050565b6008600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614612c71576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c689061525b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612ce0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cd7906152c7565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480612da05750600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b80612e0957506006600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b612e48576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e3f90615333565b60405180910390fd5b612e50613336565b600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612e9e9190614851565b92505081905550612ead613336565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550612f0383826138b3565b612f0d8282613c37565b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a48173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fe59fdd36d0d223c0c7d996db7ad796880f45e1936cb0bb7ac102e7082e031487612fbf613336565b604051612fcc9190614079565b60405180910390a350505050565b612fe2613336565b81612fed9190614e6a565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461303b9190614945565b9250508190555060005b818110156130695761305683613660565b808061306190614fd5565b915050613045565b505050565b60606000600161307d84613e39565b01905060008167ffffffffffffffff81111561309c5761309b6143e7565b5b6040519080825280601f01601f1916602001820160405280156130ce5781602001600182028036833780820191505090505b509050600082602001820190505b600115613131578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581613125576131246148e5565b5b049450600085036130dc575b819350505050919050565b613147838383613f8c565b6013546131526111df565b116132405760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614806131fc575060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b61323b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613232906153c5565b60405180910390fd5b613331565b60b46014546013546132529190614e6a565b60165461325f9190614945565b6132699190614945565b421015613330576103e87f00000000000000000000000000000000000000000000021e19e0c9bab240000060056132a09190614e6a565b6132aa9190614914565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561332b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161332290615431565b60405180910390fd5b613331565b5b505050565b60007f0000000000000000000000000000000000000000000000000000000000000012600a6133659190615584565b905090565b6000813b9050919050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16806133d457506133d38261336a565b5b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603613441576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506134d19190614851565b815481106134e2576134e161501d565b5b90600052602060002001549050600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548061353e5761353d6155cf565b5b60019003818190600052602060002001600090559055600b6000828152602001908152602001600020600090556008600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556006600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600d81908060018154018082558091505060019003906000526020600020016000909190919091505580600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036136c6576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080600d8054905003613755576003600081548092919060010191905055507f0000000000000000000000000000000000000000000000000000000000002710600354111561374b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161374290615670565b60405180910390fd5b60035490506137b0565b600d6001600d805490506137699190614851565b8154811061377a5761377961501d565b5b90600052602060002001549050600d805480613799576137986155cf565b5b600190038181906000526020600020016000905590555b600073ffffffffffffffffffffffffffffffffffffffff166008600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613849576040517f23369fa600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6138538282613c37565b808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050565b60006138be8361336a565b15613a4c57600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600a60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506139519190614851565b815481106139625761396161501d565b5b9060005260206000200154905080600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600b600085815260200190815260200160002054815481106139d4576139d361501d565b5b9060005260206000200181905550600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480613a3157613a306155cf565b5b60019003818190600052602060002001600090559055613bd1565b600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600960008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050613ada9190614851565b81548110613aeb57613aea61501d565b5b9060005260206000200154905080600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600b60008581526020019081526020016000205481548110613b5d57613b5c61501d565b5b9060005260206000200181905550600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480613bba57613bb96155cf565b5b600190038181906000526020600020016000905590555b600b600083815260200190815260200160002054600b6000838152602001908152602001600020819055506006600083815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055505050565b816008600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613c928261336a565b15613d6857600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002001600090919091909150556001600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050613d4c9190614851565b600b600083815260200190815260200160002081905550613e35565b600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002001600090919091909150556001600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050613e1d9190614851565b600b6000838152602001908152602001600020819055505b5050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613e97577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381613e8d57613e8c6148e5565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310613ed4576d04ee2d6d415b85acef81000000008381613eca57613ec96148e5565b5b0492506020810190505b662386f26fc100008310613f0357662386f26fc100008381613ef957613ef86148e5565b5b0492506010810190505b6305f5e1008310613f2c576305f5e1008381613f2257613f216148e5565b5b0492506008810190505b6127108310613f51576127108381613f4757613f466148e5565b5b0492506004810190505b60648310613f745760648381613f6a57613f696148e5565b5b0492506002810190505b600a8310613f83576001810190505b80915050919050565b505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613fda81613fa5565b8114613fe557600080fd5b50565b600081359050613ff781613fd1565b92915050565b60006020828403121561401357614012613f9b565b5b600061402184828501613fe8565b91505092915050565b60008115159050919050565b61403f8161402a565b82525050565b600060208201905061405a6000830184614036565b92915050565b6000819050919050565b61407381614060565b82525050565b600060208201905061408e600083018461406a565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156140ce5780820151818401526020810190506140b3565b60008484015250505050565b6000601f19601f8301169050919050565b60006140f682614094565b614100818561409f565b93506141108185602086016140b0565b614119816140da565b840191505092915050565b6000602082019050818103600083015261413e81846140eb565b905092915050565b61414f81614060565b811461415a57600080fd5b50565b60008135905061416c81614146565b92915050565b60006020828403121561418857614187613f9b565b5b60006141968482850161415d565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006141ca8261419f565b9050919050565b6141da816141bf565b82525050565b60006020820190506141f560008301846141d1565b92915050565b614204816141bf565b811461420f57600080fd5b50565b600081359050614221816141fb565b92915050565b6000806040838503121561423e5761423d613f9b565b5b600061424c85828601614212565b925050602061425d8582860161415d565b9150509250929050565b6000806000606084860312156142805761427f613f9b565b5b600061428e8682870161415d565b935050602061429f86828701614212565b92505060406142b08682870161415d565b9150509250925092565b6142c38161402a565b81146142ce57600080fd5b50565b6000813590506142e0816142ba565b92915050565b6000602082840312156142fc576142fb613f9b565b5b600061430a848285016142d1565b91505092915050565b60008060006060848603121561432c5761432b613f9b565b5b600061433a86828701614212565b935050602061434b86828701614212565b925050604061435c8682870161415d565b9150509250925092565b600060ff82169050919050565b61437c81614366565b82525050565b60006020820190506143976000830184614373565b92915050565b600080604083850312156143b4576143b3613f9b565b5b60006143c285828601614212565b92505060206143d3858286016142d1565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61441f826140da565b810181811067ffffffffffffffff8211171561443e5761443d6143e7565b5b80604052505050565b6000614451613f91565b905061445d8282614416565b919050565b600067ffffffffffffffff82111561447d5761447c6143e7565b5b614486826140da565b9050602081019050919050565b82818337600083830152505050565b60006144b56144b084614462565b614447565b9050828152602081018484840111156144d1576144d06143e2565b5b6144dc848285614493565b509392505050565b600082601f8301126144f9576144f86143dd565b5b81356145098482602086016144a2565b91505092915050565b60006020828403121561452857614527613f9b565b5b600082013567ffffffffffffffff81111561454657614545613fa0565b5b614552848285016144e4565b91505092915050565b60006020828403121561457157614570613f9b565b5b600061457f84828501614212565b91505092915050565b600067ffffffffffffffff8211156145a3576145a26143e7565b5b602082029050602081019050919050565b600080fd5b60006145cc6145c784614588565b614447565b905080838252602082019050602084028301858111156145ef576145ee6145b4565b5b835b8181101561461857806146048882614212565b8452602084019350506020810190506145f1565b5050509392505050565b600082601f830112614637576146366143dd565b5b81356146478482602086016145b9565b91505092915050565b60008060006060848603121561466957614668613f9b565b5b60006146778682870161415d565b935050602084013567ffffffffffffffff81111561469857614697613fa0565b5b6146a486828701614622565b92505060406146b58682870161415d565b9150509250925092565b600080604083850312156146d6576146d5613f9b565b5b60006146e48582860161415d565b92505060206146f585828601614212565b9150509250929050565b600080fd5b60008083601f84011261471a576147196143dd565b5b8235905067ffffffffffffffff811115614737576147366146ff565b5b602083019150836001820283011115614753576147526145b4565b5b9250929050565b60008060008060006080868803121561477657614775613f9b565b5b600061478488828901614212565b955050602061479588828901614212565b94505060406147a68882890161415d565b935050606086013567ffffffffffffffff8111156147c7576147c6613fa0565b5b6147d388828901614704565b92509250509295509295909350565b600080604083850312156147f9576147f8613f9b565b5b600061480785828601614212565b925050602061481885828601614212565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061485c82614060565b915061486783614060565b925082820390508181111561487f5761487e614822565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806148cc57607f821691505b6020821081036148df576148de614885565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061491f82614060565b915061492a83614060565b92508261493a576149396148e5565b5b828204905092915050565b600061495082614060565b915061495b83614060565b925082820190508082111561497357614972614822565b5b92915050565b7f4e6f7420656e6f75676820616c6c6f77616e63652e0000000000000000000000600082015250565b60006149af60158361409f565b91506149ba82614979565b602082019050919050565b600060208201905081810360008301526149de816149a2565b9050919050565b600082825260208201905092915050565b50565b6000614a066000836149e5565b9150614a11826149f6565b600082019050919050565b6000608082019050614a3160008301866141d1565b614a3e60208301856141d1565b614a4b604083018461406a565b8181036060830152614a5c816149f9565b9050949350505050565b600081519050614a7581613fd1565b92915050565b600060208284031215614a9157614a90613f9b565b5b6000614a9f84828501614a66565b91505092915050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302614b0a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614acd565b614b148683614acd565b95508019841693508086168417925050509392505050565b6000819050919050565b6000614b51614b4c614b4784614060565b614b2c565b614060565b9050919050565b6000819050919050565b614b6b83614b36565b614b7f614b7782614b58565b848454614ada565b825550505050565b600090565b614b94614b87565b614b9f818484614b62565b505050565b5b81811015614bc357614bb8600082614b8c565b600181019050614ba5565b5050565b601f821115614c0857614bd981614aa8565b614be284614abd565b81016020851015614bf1578190505b614c05614bfd85614abd565b830182614ba4565b50505b505050565b600082821c905092915050565b6000614c2b60001984600802614c0d565b1980831691505092915050565b6000614c448383614c1a565b9150826002028217905092915050565b614c5d82614094565b67ffffffffffffffff811115614c7657614c756143e7565b5b614c8082546148b4565b614c8b828285614bc7565b600060209050601f831160018114614cbe5760008415614cac578287015190505b614cb68582614c38565b865550614d1e565b601f198416614ccc86614aa8565b60005b82811015614cf457848901518255600182019150602085019450602081019050614ccf565b86831015614d115784890151614d0d601f891682614c1a565b8355505b6001600288020188555050505b505050505050565b7f4d696e74696e67206973206e6f74206163746976652e00000000000000000000600082015250565b6000614d5c60168361409f565b9150614d6782614d26565b602082019050919050565b60006020820190508181036000830152614d8b81614d4f565b9050919050565b7f43616e6e6f74206d696e742074686174206d616e79206174206f6e63652e0000600082015250565b6000614dc8601e8361409f565b9150614dd382614d92565b602082019050919050565b60006020820190508181036000830152614df781614dbb565b9050919050565b7f46696e6973686564206d696e74696e672e000000000000000000000000000000600082015250565b6000614e3460118361409f565b9150614e3f82614dfe565b602082019050919050565b60006020820190508181036000830152614e6381614e27565b9050919050565b6000614e7582614060565b9150614e8083614060565b9250828202614e8e81614060565b91508282048414831517614ea557614ea4614822565b5b5092915050565b7f4e6f7420656e6f7567682046544d2073656e742e000000000000000000000000600082015250565b6000614ee260148361409f565b9150614eed82614eac565b602082019050919050565b60006020820190508181036000830152614f1181614ed5565b9050919050565b7f43757272656e746c7920696e2070686173652000000000000000000000000000815250565b600081905092915050565b6000614f5482614094565b614f5e8185614f3e565b9350614f6e8185602086016140b0565b80840191505092915050565b7f2e00000000000000000000000000000000000000000000000000000000000000815250565b6000614fab82614f18565b601382019150614fbb8284614f49565b9150614fc682614f7a565b60018201915081905092915050565b6000614fe082614060565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361501257615011614822565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061505883856149e5565b9350615065838584614493565b61506e836140da565b840190509392505050565b600060808201905061508e60008301886141d1565b61509b60208301876141d1565b6150a8604083018661406a565b81810360608301526150bb81848661504c565b90509695505050505050565b600081546150d4816148b4565b6150de8186614f3e565b945060018216600081146150f9576001811461510e57615141565b60ff1983168652811515820286019350615141565b61511785614aa8565b60005b838110156151395781548189015260018201915060208101905061511a565b838801955050505b50505092915050565b7f2e6a736f6e000000000000000000000000000000000000000000000000000000815250565b600061517c82856150c7565b91506151888284614f49565b91506151938261514a565b6005820191508190509392505050565b7f4e6f7420656e6f75676820746f6b656e2062616c616e63652e00000000000000600082015250565b60006151d960198361409f565b91506151e4826151a3565b602082019050919050565b60006020820190508181036000830152615208816151cc565b9050919050565b7f53656e646572206973206e6f74206f776e6572206f66204e46542e0000000000600082015250565b6000615245601b8361409f565b91506152508261520f565b602082019050919050565b6000602082019050818103600083015261527481615238565b9050919050565b7f43616e6e6f742073656e6420746f206e756c6c20616464726573732e00000000600082015250565b60006152b1601c8361409f565b91506152bc8261527b565b602082019050919050565b600060208201905081810360008301526152e0816152a4565b9050919050565b7f4f70657261746f72206973206e6f7420617070726f7665642e00000000000000600082015250565b600061531d60198361409f565b9150615328826152e7565b602082019050919050565b6000602082019050818103600083015261534c81615310565b9050919050565b7f43616e6e6f74207472616e7366657220756e74696c206d696e7420656e74657260008201527f73207075626c69632e0000000000000000000000000000000000000000000000602082015250565b60006153af60298361409f565b91506153ba82615353565b604082019050919050565b600060208201905081810360008301526153de816153a2565b9050919050565b7f4e6f206d6f7265207468616e20302e352520617420746869732073746167652e600082015250565b600061541b60208361409f565b9150615426826153e5565b602082019050919050565b6000602082019050818103600083015261544a8161540e565b9050919050565b60008160011c9050919050565b6000808291508390505b60018511156154a85780860481111561548457615483614822565b5b60018516156154935780820291505b80810290506154a185615451565b9450615468565b94509492505050565b6000826154c1576001905061557d565b816154cf576000905061557d565b81600181146154e557600281146154ef5761551e565b600191505061557d565b60ff84111561550157615500614822565b5b8360020a91508482111561551857615517614822565b5b5061557d565b5060208310610133831016604e8410600b84101617156155535782820a90508381111561554e5761554d614822565b5b61557d565b615560848484600161545e565b9250905081840481111561557757615576614822565b5b81810290505b9392505050565b600061558f82614060565b915061559a83614366565b92506155c77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84846154b1565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f43616e6e6f74206d696e74206d6f7265207468616e20676976656e207375707060008201527f6c792e0000000000000000000000000000000000000000000000000000000000602082015250565b600061565a60238361409f565b9150615665826155fe565b604082019050919050565b600060208201905081810360008301526156898161564d565b905091905056fea26469706673582212206593f69164f97361fef760970602d8233d62eb5e1907650df55805aa77e5528464736f6c63430008140033

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

00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000001600000000000000000000000004a8ddd9b108f5ba439a7b461b6036c20f0737342000000000000000000000000000000000000000000000000000000006761f2d10000000000000000000000000000000000000000000000000000000000000004486177670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044841574700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004468747470733a2f2f697066732e696f2f697066732f516d665a72374471553563566e74386431486874743543756a44323578613875424665396b713374527a617056422f00000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : name (string): Hawg
Arg [1] : symbol (string): HAWG
Arg [2] : decimals (uint8): 18
Arg [3] : supply (uint256): 10000
Arg [4] : _baseTokenURI (string): https://ipfs.io/ipfs/QmfZr7DqU5cVnt8d1Hhtt5CujD25xa8uBFe9kq3tRzapVB/
Arg [5] : _owner (address): 0x4a8Ddd9B108f5Ba439A7B461B6036c20f0737342
Arg [6] : _startTime (uint256): 1734472401

-----Encoded View---------------
15 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [3] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [5] : 0000000000000000000000004a8ddd9b108f5ba439a7b461b6036c20f0737342
Arg [6] : 000000000000000000000000000000000000000000000000000000006761f2d1
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [8] : 4861776700000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [10] : 4841574700000000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000044
Arg [12] : 68747470733a2f2f697066732e696f2f697066732f516d665a72374471553563
Arg [13] : 566e74386431486874743543756a44323578613875424665396b713374527a61
Arg [14] : 7056422f00000000000000000000000000000000000000000000000000000000


[ 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.