ETH Price: $3,457.11 (-0.86%)

Token

 

Overview

Max Total Supply

8,527

Holders

1,442

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
0x7cf5d755c93817af7cfc7a883c666fb01ad80942
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
MMCNFTV2

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
No with 200 runs

Other Settings:
shanghai EvmVersion
File 1 of 26 : MMCNFTV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract MMCNFTV2 is ERC1155, Ownable, ERC1155Burnable, ERC1155Supply, IERC1155Receiver, ReentrancyGuard {
    using SafeERC20 for IERC20;
    using Strings for uint256;

    IUniswapV2Router02 public uniswapV2Router;
    IUniswapV2Factory public uniswapV2Factory;

    // Token information structure
    struct TokenInfo {
        uint256 price;
        uint8 tokenType;
        uint8 status;
        string uri;
    }

    // Mapping of Token ID to TokenInfo
    mapping(uint256 => TokenInfo) public tokenInfo;

    // Pool percentage, default 50%
    uint256 public poolPercentage = 50;
    // Withdrawable USDT balance
    uint256 public withdrawableUSDT;
    // Selling status
    uint8 public saleStatus;

    // Interface for USDT and MMC tokens
    IERC20 public usdtToken;
    IERC20 public mmcToken;

    // Constructor to initialize Uniswap router, factory and token address
    constructor(address _router, address _factory, address _usdtToken, address _mmcToken) ERC1155("") Ownable(msg.sender) {
        uniswapV2Router = IUniswapV2Router02(_router);
        uniswapV2Factory = IUniswapV2Factory(_factory);
        usdtToken = IERC20(_usdtToken);
        mmcToken = IERC20(_mmcToken);
    }

    // Add liquidity
    function uniAddLiquidity(
        address _tokenA,
        address _tokenB,
        uint256 _amountA,
        uint256 _amountB,
        uint256 _minAmountA,
        uint256 _minAmountB
    ) external onlyOwner {
        // Check if _tokenA is USDT and ensure not to use withdrawable USDT
        uint256 usdtBalance = usdtToken.balanceOf(address(this)) - withdrawableUSDT;

        if (_tokenA == address(usdtToken)) {
            require(_amountA <= usdtBalance, "Invalid request");
        }

        // Check if _tokenB is USDT and ensure not to use withdrawable USDT
        if (_tokenB == address(usdtToken)) {
            require(_amountB <= usdtBalance, "Invalid request");
        }

        // Safe increase allowance
        IERC20(_tokenA).safeIncreaseAllowance(address(uniswapV2Router), _amountA);
        IERC20(_tokenB).safeIncreaseAllowance(address(uniswapV2Router), _amountB);

        // Add liquidity
        uniswapV2Router.addLiquidity(
            _tokenA,
            _tokenB,
            _amountA,
            _amountB,
            _minAmountA,
            _minAmountB,
            address(this),
            block.timestamp + 15 minutes
        );
    }


    // Remove Liquidity
    function uniRemoveLiquidity(
        address _tokenA,
        address _tokenB,
        uint256 _liquidity,
        uint256 _minAmountA,
        uint256 _minAmountB
    ) external onlyOwner {

        address pairAddress = uniswapV2Factory.getPair(_tokenA, _tokenB);
        require(pairAddress != address(0), "Invalid request");

        IERC20(pairAddress).safeIncreaseAllowance(address(uniswapV2Router), _liquidity);
        // Remove Liquidity
        uniswapV2Router.removeLiquidity(
            _tokenA,
            _tokenB,
            _liquidity,
            _minAmountA,
            _minAmountB,
            address(this),
            block.timestamp + 15 minutes
        );
    }

    // Exchange USDT <=> MMC
    function swapExchangeToken(
        uint amountIn,         // The amount of USDT entered
        uint amountOutMin,     // Minimum expected number of MMCs to receive
        uint8 swapType         // 0: Buy 1: Sell
    ) external onlyOwner {
        address[] memory path = new address[](2);
        if (swapType == 0) {
            // USDT => MMC
            require(amountIn <= usdtToken.balanceOf(address(this)) - withdrawableUSDT, "Invalid request");
            usdtToken.safeIncreaseAllowance(address(uniswapV2Router), amountIn);
            path[0] = address(usdtToken);
            path[1] = address(mmcToken);
        } else {
            // MMC => USDT
            mmcToken.safeIncreaseAllowance(address(uniswapV2Router), amountIn);
            path[0] = address(mmcToken);
            path[1] = address(usdtToken);

        }

        uniswapV2Router.swapExactTokensForTokens(
            amountIn,
            amountOutMin,
            path,
            address(this),
            block.timestamp + 15 minutes
        );
    }

    // Set base URI
    function setBaseURI(string memory newUri) external onlyOwner {
        _setURI(newUri);
    }

    // Implementing the ERC1155 receiver interface
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    )
    external
    override
    returns(bytes4)
    {
        return this.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    )
    external
    override
    returns(bytes4)
    {
        return this.onERC1155BatchReceived.selector;
    }

    // Set Token URI in batches
    function setTokenURIBatch(uint256[] memory tokenIds, string[] memory newUris) external onlyOwner {
        require(tokenIds.length == newUris.length, "Invalid request");
        for (uint256 i = 0; i < tokenIds.length; i++) {
            tokenInfo[tokenIds[i]].uri = newUris[i];
        }
    }

    // Get Token URI
    function uri(uint256 tokenId) public view override returns (string memory) {
        string memory _uri = tokenInfo[tokenId].uri;
        string memory base = super.uri(tokenId);
        return bytes(_uri).length > 0 ? string(abi.encodePacked(base, _uri)) : string(abi.encodePacked(base, tokenId.toString()));
    }


    // Mint Tokens in batches and set URI, price, and type
    function mintBatchWithUri(address to, uint256[] memory ids, uint256[] memory amounts, string[] memory tokenUris, uint256[] memory prices, uint8[] memory types, uint8[] memory statuses, bytes memory data) public onlyOwner {
        require(ids.length == amounts.length && ids.length == tokenUris.length && ids.length == prices.length && ids.length == types.length && ids.length == statuses.length, "Invalid request");
        for (uint256 i = 0; i < ids.length; i++) {
            require(!exists(ids[i]), "Token ID already exists"); // Check if the token already exists
            tokenInfo[ids[i]] = TokenInfo(prices[i], types[i], statuses[i], tokenUris[i]);
        }
        _mintBatch(to, ids, amounts, data);
    }

    // Secure transfer of tokens
    function safeTransfer(address to, uint256 tokenId, uint256 amount, bytes memory data) external onlyOwner {
        safeTransferFrom(msg.sender, to, tokenId, amount, data);
    }

    // Transfer token from contract
    function safeTransferContract(address to, uint256 tokenId, uint256 amount, bytes memory data) external onlyOwner {
        _safeTransferFrom(address(this), to, tokenId, amount, data);
    }

    // Destroy the NFT in the contract
    function destroyContractNFT(uint256 tokenId, uint256 amount) external onlyOwner {
        _burn(address(this), tokenId, amount);
    }

    // Update function, overrides the update function of the parent class
    function _update(address from, address to, uint256[] memory ids, uint256[] memory values)
    internal
    override(ERC1155, ERC1155Supply)
    {
        super._update(from, to, ids, values);
    }

    // Set the pool entry percentage, ranging from 50% to 100%
    function setPoolPercentage(uint256 _percentage) external onlyOwner {
        // 50 and 100
        require(_percentage >= 50 && _percentage <= 100, "Invalid request");
        poolPercentage = _percentage;
    }

    // Set sales status, global switch
    function setSaleStatus(uint8 _status) external onlyOwner {
        // 0 or 1
        require(_status == 0 || _status == 1, "Invalid request");
        saleStatus = _status;
    }

    // Set Token status
    function setTokenStatus(uint256 tokenId, uint8 status) external onlyOwner {
        require(status == 0 || status == 1, "Invalid request");
        tokenInfo[tokenId].status = status;
    }


    // Purchase NFT tokenId: NFT ID quantity: NFT Number
    function buyNFT(address to, uint256 tokenId, uint256 quantity, bytes memory data) external nonReentrant {
        require(to != address(0) && quantity > 0 && saleStatus == 1 && tokenInfo[tokenId].status == 1, "Invalid request");
        // Check if the contract has enough NFT balance

        uint256 totalAmount = tokenInfo[tokenId].price * quantity;
        require(balanceOf(address(this), tokenId) >= quantity && usdtToken.allowance(msg.sender, address(this)) >= totalAmount && usdtToken.balanceOf(msg.sender) >= totalAmount, "Invalid request");

        usdtToken.safeTransferFrom(msg.sender, address(this), totalAmount);
        if (tokenInfo[tokenId].tokenType == 1) {
            withdrawableUSDT += totalAmount - ((totalAmount * poolPercentage) / 100);
        }
        _safeTransferFrom(address(this), to, tokenId, quantity, data);
    }

    // Withdraw your withdrawable USDT balance
    function withdrawUSDT(address to, uint256 amount) external onlyOwner nonReentrant {
        require(to != address(0) && amount <= withdrawableUSDT, "Invalid request");
        // Update the state before transferring the tokens
        withdrawableUSDT -= amount;
        // Transfer USDT to the specified address
        usdtToken.safeTransfer(to, amount);
    }

    // Receive ERC20 tokens
    function receiveERC20(IERC20 _token, uint256 amount) external {
        _token.transferFrom(msg.sender, address(this), amount);
    }


}

File 2 of 26 : IUniswapV2Router02.sol
pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

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

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

File 3 of 26 : IUniswapV2Router01.sol
pragma solidity >=0.6.2;

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

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

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

File 4 of 26 : IUniswapV2Pair.sol
pragma solidity >=0.5.0;

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

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

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

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

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

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

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

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

    function initialize(address, address) external;
}

File 5 of 26 : IUniswapV2Factory.sol
pragma solidity >=0.5.0;

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

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

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

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

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

File 6 of 26 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

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

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

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

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

File 7 of 26 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 8 of 26 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

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

File 9 of 26 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./IERC165.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 10 of 26 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.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));
    }
}

File 11 of 26 : StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

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

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

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

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

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

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

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

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

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

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

File 12 of 26 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

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

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

    uint256 private _status;

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

    constructor() {
        _status = NOT_ENTERED;
    }

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

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

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

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

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

File 13 of 26 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)

pragma solidity ^0.8.20;

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

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

File 14 of 26 : Arrays.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol)

pragma solidity ^0.8.20;

import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";

/**
 * @dev Collection of functions related to array types.
 */
library Arrays {
    using StorageSlot for bytes32;

    /**
     * @dev Searches a sorted `array` and returns the first index that contains
     * a value greater or equal to `element`. If no such index exists (i.e. all
     * values in the array are strictly less than `element`), the array length is
     * returned. Time complexity O(log n).
     *
     * `array` is expected to be sorted in ascending order, and to contain no
     * repeated elements.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && unsafeAccess(array, low - 1).value == element) {
            return low - 1;
        } else {
            return low;
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getAddressSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getBytes32Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getUint256Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }
}

File 15 of 26 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

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

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

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

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

File 16 of 26 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

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

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

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

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

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

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

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

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

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

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

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

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

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

File 17 of 26 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

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

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

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

File 18 of 26 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

File 19 of 26 : IERC1155MetadataURI.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol)

pragma solidity ^0.8.20;

import {IERC1155} from "../IERC1155.sol";

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 */
interface IERC1155MetadataURI is IERC1155 {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

File 20 of 26 : ERC1155Supply.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Supply.sol)

pragma solidity ^0.8.20;

import {ERC1155} from "../ERC1155.sol";

/**
 * @dev Extension of ERC1155 that adds tracking of total supply per id.
 *
 * Useful for scenarios where Fungible and Non-fungible tokens have to be
 * clearly identified. Note: While a totalSupply of 1 might mean the
 * corresponding is an NFT, there is no guarantees that no other token with the
 * same id are not going to be minted.
 *
 * NOTE: This contract implies a global limit of 2**256 - 1 to the number of tokens
 * that can be minted.
 *
 * CAUTION: This extension should not be added in an upgrade to an already deployed contract.
 */
abstract contract ERC1155Supply is ERC1155 {
    mapping(uint256 id => uint256) private _totalSupply;
    uint256 private _totalSupplyAll;

    /**
     * @dev Total value of tokens in with a given id.
     */
    function totalSupply(uint256 id) public view virtual returns (uint256) {
        return _totalSupply[id];
    }

    /**
     * @dev Total value of tokens.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupplyAll;
    }

    /**
     * @dev Indicates whether any token exist with a given id, or not.
     */
    function exists(uint256 id) public view virtual returns (bool) {
        return totalSupply(id) > 0;
    }

    /**
     * @dev See {ERC1155-_update}.
     */
    function _update(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values
    ) internal virtual override {
        super._update(from, to, ids, values);

        if (from == address(0)) {
            uint256 totalMintValue = 0;
            for (uint256 i = 0; i < ids.length; ++i) {
                uint256 value = values[i];
                // Overflow check required: The rest of the code assumes that totalSupply never overflows
                _totalSupply[ids[i]] += value;
                totalMintValue += value;
            }
            // Overflow check required: The rest of the code assumes that totalSupplyAll never overflows
            _totalSupplyAll += totalMintValue;
        }

        if (to == address(0)) {
            uint256 totalBurnValue = 0;
            for (uint256 i = 0; i < ids.length; ++i) {
                uint256 value = values[i];

                unchecked {
                    // Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i])
                    _totalSupply[ids[i]] -= value;
                    // Overflow not possible: sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll
                    totalBurnValue += value;
                }
            }
            unchecked {
                // Overflow not possible: totalBurnValue = sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll
                _totalSupplyAll -= totalBurnValue;
            }
        }
    }
}

File 21 of 26 : ERC1155Burnable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Burnable.sol)

pragma solidity ^0.8.20;

import {ERC1155} from "../ERC1155.sol";

/**
 * @dev Extension of {ERC1155} that allows token holders to destroy both their
 * own tokens and those that they have been approved to use.
 */
abstract contract ERC1155Burnable is ERC1155 {
    function burn(address account, uint256 id, uint256 value) public virtual {
        if (account != _msgSender() && !isApprovedForAll(account, _msgSender())) {
            revert ERC1155MissingApprovalForAll(_msgSender(), account);
        }

        _burn(account, id, value);
    }

    function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual {
        if (account != _msgSender() && !isApprovedForAll(account, _msgSender())) {
            revert ERC1155MissingApprovalForAll(_msgSender(), account);
        }

        _burnBatch(account, ids, values);
    }
}

File 22 of 26 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 23 of 26 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the value of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155Received} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external;
}

File 24 of 26 : ERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol)

pragma solidity ^0.8.20;

import {IERC1155} from "./IERC1155.sol";
import {IERC1155Receiver} from "./IERC1155Receiver.sol";
import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol";
import {Context} from "../../utils/Context.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {Arrays} from "../../utils/Arrays.sol";
import {IERC1155Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 */
abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors {
    using Arrays for uint256[];
    using Arrays for address[];

    mapping(uint256 id => mapping(address account => uint256)) private _balances;

    mapping(address account => mapping(address operator => bool)) private _operatorApprovals;

    // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
    string private _uri;

    /**
     * @dev See {_setURI}.
     */
    constructor(string memory uri_) {
        _setURI(uri_);
    }

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

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256 /* id */) public view virtual returns (string memory) {
        return _uri;
    }

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

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] memory accounts,
        uint256[] memory ids
    ) public view virtual returns (uint256[] memory) {
        if (accounts.length != ids.length) {
            revert ERC1155InvalidArrayLength(ids.length, accounts.length);
        }

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
        return _operatorApprovals[account][operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
        address sender = _msgSender();
        if (from != sender && !isApprovedForAll(from, sender)) {
            revert ERC1155MissingApprovalForAll(sender, from);
        }
        _safeTransferFrom(from, to, id, value, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) public virtual {
        address sender = _msgSender();
        if (from != sender && !isApprovedForAll(from, sender)) {
            revert ERC1155MissingApprovalForAll(sender, from);
        }
        _safeBatchTransferFrom(from, to, ids, values, data);
    }

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
     * (or `to`) is the zero address.
     *
     * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
     *   or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
     * - `ids` and `values` must have the same length.
     *
     * NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
     */
    function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
        if (ids.length != values.length) {
            revert ERC1155InvalidArrayLength(ids.length, values.length);
        }

        address operator = _msgSender();

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids.unsafeMemoryAccess(i);
            uint256 value = values.unsafeMemoryAccess(i);

            if (from != address(0)) {
                uint256 fromBalance = _balances[id][from];
                if (fromBalance < value) {
                    revert ERC1155InsufficientBalance(from, fromBalance, value, id);
                }
                unchecked {
                    // Overflow not possible: value <= fromBalance
                    _balances[id][from] = fromBalance - value;
                }
            }

            if (to != address(0)) {
                _balances[id][to] += value;
            }
        }

        if (ids.length == 1) {
            uint256 id = ids.unsafeMemoryAccess(0);
            uint256 value = values.unsafeMemoryAccess(0);
            emit TransferSingle(operator, from, to, id, value);
        } else {
            emit TransferBatch(operator, from, to, ids, values);
        }
    }

    /**
     * @dev Version of {_update} that performs the token acceptance check by calling
     * {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it
     * contains code (eg. is a smart contract at the moment of execution).
     *
     * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
     * update to the contract state after this function would break the check-effect-interaction pattern. Consider
     * overriding {_update} instead.
     */
    function _updateWithAcceptanceCheck(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal virtual {
        _update(from, to, ids, values);
        if (to != address(0)) {
            address operator = _msgSender();
            if (ids.length == 1) {
                uint256 id = ids.unsafeMemoryAccess(0);
                uint256 value = values.unsafeMemoryAccess(0);
                _doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
            } else {
                _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
            }
        }
    }

    /**
     * @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     * - `ids` and `values` must have the same length.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        _updateWithAcceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the values in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory newuri) internal virtual {
        _uri = newuri;
    }

    /**
     * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(address(0), to, ids, values, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        _updateWithAcceptanceCheck(address(0), to, ids, values, data);
    }

    /**
     * @dev Destroys a `value` amount of tokens of type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `value` amount of tokens of type `id`.
     */
    function _burn(address from, uint256 id, uint256 value) internal {
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(from, address(0), ids, values, "");
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `value` amount of tokens of type `id`.
     * - `ids` and `values` must have the same length.
     */
    function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        _updateWithAcceptanceCheck(from, address(0), ids, values, "");
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the zero address.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        if (operator == address(0)) {
            revert ERC1155InvalidOperator(address(0));
        }
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
     * if it contains code at the moment of execution.
     */
    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 value,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    // Tokens rejected
                    revert ERC1155InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-ERC1155Receiver implementer
                    revert ERC1155InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /**
     * @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
     * if it contains code at the moment of execution.
     */
    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    // Tokens rejected
                    revert ERC1155InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-ERC1155Receiver implementer
                    revert ERC1155InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /**
     * @dev Creates an array in memory with only one value for each of the elements provided.
     */
    function _asSingletonArrays(
        uint256 element1,
        uint256 element2
    ) private pure returns (uint256[] memory array1, uint256[] memory array2) {
        /// @solidity memory-safe-assembly
        assembly {
            // Load the free memory pointer
            array1 := mload(0x40)
            // Set array length to 1
            mstore(array1, 1)
            // Store the single element at the next word after the length (where content starts)
            mstore(add(array1, 0x20), element1)

            // Repeat for next array locating it right after the first array
            array2 := add(array1, 0x40)
            mstore(array2, 1)
            mstore(add(array2, 0x20), element2)

            // Update the free memory pointer by pointing after the second array
            mstore(0x40, add(array2, 0x40))
        }
    }
}

File 25 of 26 : draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 26 of 26 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

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

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

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

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

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

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

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

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

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

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

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

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_usdtToken","type":"address"},{"internalType":"address","name":"_mmcToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC1155InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC1155InvalidApprover","type":"error"},{"inputs":[{"internalType":"uint256","name":"idsLength","type":"uint256"},{"internalType":"uint256","name":"valuesLength","type":"uint256"}],"name":"ERC1155InvalidArrayLength","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC1155InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC1155InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC1155InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC1155MissingApprovalForAll","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","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":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"burnBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"buyNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"destroyContractNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"string[]","name":"tokenUris","type":"string[]"},{"internalType":"uint256[]","name":"prices","type":"uint256[]"},{"internalType":"uint8[]","name":"types","type":"uint8[]"},{"internalType":"uint8[]","name":"statuses","type":"uint8[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mintBatchWithUri","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mmcToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"receiveERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferContract","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":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"saleStatus","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"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":"newUri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_percentage","type":"uint256"}],"name":"setPoolPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_status","type":"uint8"}],"name":"setSaleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"}],"name":"setTokenStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"string[]","name":"newUris","type":"string[]"}],"name":"setTokenURIBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint8","name":"swapType","type":"uint8"}],"name":"swapExchangeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenInfo","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"tokenType","type":"uint8"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"},{"internalType":"uint256","name":"_amountA","type":"uint256"},{"internalType":"uint256","name":"_amountB","type":"uint256"},{"internalType":"uint256","name":"_minAmountA","type":"uint256"},{"internalType":"uint256","name":"_minAmountB","type":"uint256"}],"name":"uniAddLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"},{"internalType":"uint256","name":"_liquidity","type":"uint256"},{"internalType":"uint256","name":"_minAmountA","type":"uint256"},{"internalType":"uint256","name":"_minAmountB","type":"uint256"}],"name":"uniRemoveLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV2Factory","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapV2Router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdtToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawUSDT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawableUSDT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040526032600a5534801562000015575f80fd5b50604051620066bd380380620066bd83398181016040528101906200003b919062000332565b3360405180602001604052805f8152506200005c81620001f560201b60201c565b505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000d0575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401620000c79190620003b2565b60405180910390fd5b620000e1816200020a60201b60201c565b5060016006819055508360075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600c60016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600d5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505062000715565b806002908162000206919062000631565b5050565b5f60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160035f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f620002fc82620002d1565b9050919050565b6200030e81620002f0565b811462000319575f80fd5b50565b5f815190506200032c8162000303565b92915050565b5f805f80608085870312156200034d576200034c620002cd565b5b5f6200035c878288016200031c565b94505060206200036f878288016200031c565b935050604062000382878288016200031c565b925050606062000395878288016200031c565b91505092959194509250565b620003ac81620002f0565b82525050565b5f602082019050620003c75f830184620003a1565b92915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200044957607f821691505b6020821081036200045f576200045e62000404565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004c37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000486565b620004cf868362000486565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000519620005136200050d84620004e7565b620004f0565b620004e7565b9050919050565b5f819050919050565b6200053483620004f9565b6200054c620005438262000520565b84845462000492565b825550505050565b5f90565b6200056262000554565b6200056f81848462000529565b505050565b5b8181101562000596576200058a5f8262000558565b60018101905062000575565b5050565b601f821115620005e557620005af8162000465565b620005ba8462000477565b81016020851015620005ca578190505b620005e2620005d98562000477565b83018262000574565b50505b505050565b5f82821c905092915050565b5f620006075f1984600802620005ea565b1980831691505092915050565b5f620006218383620005f6565b9150826002028217905092915050565b6200063c82620003cd565b67ffffffffffffffff811115620006585762000657620003d7565b5b62000664825462000431565b620006718282856200059a565b5f60209050601f831160018114620006a7575f841562000692578287015190505b6200069e858262000614565b8655506200070d565b601f198416620006b78662000465565b5f5b82811015620006e057848901518255600182019150602085019450602081019050620006b9565b86831015620007005784890151620006fc601f891682620005f6565b8355505b6001600288020188555050505b505050505050565b615f9a80620007235f395ff3fe608060405234801561000f575f80fd5b5060043610610250575f3560e01c8063715018a611610144578063bd85b039116100c1578063f23a6e6111610085578063f23a6e61146106dd578063f242432a1461070d578063f2fde38b14610729578063f5298aca14610745578063f807427d14610761578063f9020e331461077d57610250565b8063bd85b03914610612578063c4d32bf314610642578063cc33c8751461065e578063cf8ca74114610691578063e985e9c5146106ad57610250565b8063a8275ada11610108578063a8275ada14610570578063a98ad46c1461058c578063ae28b68c146105aa578063aed4aab6146105c6578063bc197c81146105e257610250565b8063715018a6146104f457806386f5c0d8146104fe5780638d8a818c1461051a5780638da5cb5b14610536578063a22cb4651461055457610250565b80633d54353a116101d25780634f558e79116101965780634f558e791461045257806355f804b31461048257806359d0f7131461049e5780636b20c454146104bc5780636b421a50146104d857610250565b80633d54353a146103ae5780633e7e30ba146103cc5780634891ad88146103ea5780634bb99351146104065780634e1273f41461042257610250565b80631694505e116102195780631694505e1461031c57806318160ddd1461033a5780632e6ceabe146103585780632eb2c2d61461037457806334b633ce1461039057610250565b8062fdd58e1461025457806301ffc9a7146102845780630e89341c146102b457806312d6f800146102e45780631481794e14610300575b5f80fd5b61026e60048036038101906102699190613e49565b61079b565b60405161027b9190613e96565b60405180910390f35b61029e60048036038101906102999190613f04565b6107f0565b6040516102ab9190613f49565b60405180910390f35b6102ce60048036038101906102c99190613f62565b6108d1565b6040516102db9190614017565b60405180910390f35b6102fe60048036038101906102f99190614499565b6109e0565b005b61031a60048036038101906103159190613e49565b610c14565b005b610324610d12565b6040516103319190614669565b60405180910390f35b610342610d37565b60405161034f9190613e96565b60405180910390f35b610372600480360381019061036d9190614682565b610d40565b005b61038e6004803603810190610389919061470b565b61107d565b005b610398611124565b6040516103a59190613e96565b60405180910390f35b6103b661112a565b6040516103c391906147f6565b60405180910390f35b6103d461114f565b6040516103e19190613e96565b60405180910390f35b61040460048036038101906103ff919061480f565b611155565b005b610420600480360381019061041b919061483a565b6111cd565b005b61043c60048036038101906104379190614970565b611292565b6040516104499190614a9d565b60405180910390f35b61046c60048036038101906104679190613f62565b61139f565b6040516104799190613f49565b60405180910390f35b61049c60048036038101906104979190614abd565b6113b2565b005b6104a66113c6565b6040516104b39190614b24565b60405180910390f35b6104d660048036038101906104d19190614b3d565b6113eb565b005b6104f260048036038101906104ed9190614bc5565b611497565b005b6104fc6116b3565b005b61051860048036038101906105139190614c3c565b6116c6565b005b610534600480360381019061052f9190614cbc565b611a22565b005b61053e611a39565b60405161054b9190614d09565b60405180910390f35b61056e60048036038101906105699190614d4c565b611a61565b005b61058a60048036038101906105859190613f62565b611a77565b005b610594611ada565b6040516105a191906147f6565b60405180910390f35b6105c460048036038101906105bf9190614c3c565b611b00565b005b6105e060048036038101906105db9190614dc5565b611b1b565b005b6105fc60048036038101906105f79190614eb1565b611b9d565b6040516106099190614f97565b60405180910390f35b61062c60048036038101906106279190613f62565b611bb4565b6040516106399190613e96565b60405180910390f35b61065c60048036038101906106579190614fb0565b611bce565b005b61067860048036038101906106739190613f62565b612070565b604051610688949392919061500f565b60405180910390f35b6106ab60048036038101906106a69190614c3c565b61213b565b005b6106c760048036038101906106c29190615059565b612156565b6040516106d49190613f49565b60405180910390f35b6106f760048036038101906106f29190615097565b6121e4565b6040516107049190614f97565b60405180910390f35b6107276004803603810190610722919061512d565b6121f9565b005b610743600480360381019061073e91906151c0565b6122a0565b005b61075f600480360381019061075a91906151eb565b612324565b005b61077b6004803603810190610776919061523b565b6123d0565b005b61078561245c565b6040516107929190615279565b60405180910390f35b5f805f8381526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f7fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806108ba57507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108ca57506108c98261246e565b5b9050919050565b60605f60095f8481526020019081526020015f2060020180546108f3906152bf565b80601f016020809104026020016040519081016040528092919081815260200182805461091f906152bf565b801561096a5780601f106109415761010080835404028352916020019161096a565b820191905f5260205f20905b81548152906001019060200180831161094d57829003601f168201915b505050505090505f61097b846124d7565b90505f8251116109b4578061098f85612569565b6040516020016109a0929190615329565b6040516020818303038152906040526109d7565b80826040516020016109c7929190615329565b6040516020818303038152906040525b92505050919050565b6109e8612633565b855187511480156109fa575084518751145b8015610a07575083518751145b8015610a14575082518751145b8015610a21575081518751145b610a60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5790615396565b60405180910390fd5b5f5b8751811015610bfd57610a8e888281518110610a8157610a806153b4565b5b602002602001015161139f565b15610ace576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ac59061542b565b60405180910390fd5b6040518060800160405280868381518110610aec57610aeb6153b4565b5b60200260200101518152602001858381518110610b0c57610b0b6153b4565b5b602002602001015160ff168152602001848381518110610b2f57610b2e6153b4565b5b602002602001015160ff168152602001878381518110610b5257610b516153b4565b5b602002602001015181525060095f8a8481518110610b7357610b726153b4565b5b602002602001015181526020019081526020015f205f820151815f01556020820151816001015f6101000a81548160ff021916908360ff16021790555060408201518160010160016101000a81548160ff021916908360ff1602179055506060820151816002019081610be691906155dd565b509050508080610bf5906156d9565b915050610a62565b50610c0a888888846126ba565b5050505050505050565b610c1c612633565b610c2461273d565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610c625750600b548111155b610ca1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9890615396565b60405180910390fd5b80600b5f828254610cb29190615720565b92505081905550610d068282600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166127839092919063ffffffff16565b610d0e612802565b5050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f600554905090565b610d48612633565b5f600b54600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610da79190614d09565b602060405180830381865afa158015610dc2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610de69190615767565b610df09190615720565b9050600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603610e8b5780851115610e8a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e8190615396565b60405180910390fd5b5b600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603610f245780841115610f23576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1a90615396565b60405180910390fd5b5b610f7060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16868973ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b610fbc60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16858873ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e8e33700888888888888306103844261100e9190615792565b6040518963ffffffff1660e01b81526004016110319897969594939291906157c5565b6060604051808303815f875af115801561104d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110719190615841565b50505050505050505050565b5f6110866128a5565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580156110cb57506110c98682612156565b155b1561110f5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401611106929190615891565b60405180910390fd5b61111c86868686866128ac565b505050505050565b600b5481565b600d5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600a5481565b61115d612633565b5f8160ff161480611171575060018160ff16145b6111b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111a790615396565b60405180910390fd5b80600c5f6101000a81548160ff021916908360ff16021790555050565b6111d5612633565b8051825114611219576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121090615396565b60405180910390fd5b5f5b825181101561128d57818181518110611237576112366153b4565b5b602002602001015160095f858481518110611255576112546153b4565b5b602002602001015181526020019081526020015f20600201908161127991906155dd565b508080611285906156d9565b91505061121b565b505050565b606081518351146112de57815183516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016112d59291906158b8565b60405180910390fd5b5f835167ffffffffffffffff8111156112fa576112f961403b565b5b6040519080825280602002602001820160405280156113285781602001602082028036833780820191505090505b5090505f5b84518110156113945761136461134c82876129a090919063ffffffff16565b61135f83876129b390919063ffffffff16565b61079b565b828281518110611377576113766153b4565b5b6020026020010181815250508061138d906156d9565b905061132d565b508091505092915050565b5f806113aa83611bb4565b119050919050565b6113ba612633565b6113c3816129c6565b50565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6113f36128a5565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561143c575061143a836114356128a5565b612156565b155b15611487576114496128a5565b836040517fe237d92200000000000000000000000000000000000000000000000000000000815260040161147e929190615891565b60405180910390fd5b6114928383836129d9565b505050565b61149f612633565b5f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e6a4390587876040518363ffffffff1660e01b81526004016114fc929190615891565b602060405180830381865afa158015611517573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061153b91906158f3565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036115ab576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115a290615396565b60405180910390fd5b6115f760075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16858373ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663baa2abde878787878730610384426116489190615792565b6040518863ffffffff1660e01b815260040161166a979695949392919061591e565b60408051808303815f875af1158015611685573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116a9919061598b565b5050505050505050565b6116bb612633565b6116c45f612a69565b565b6116ce61273d565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415801561170957505f82115b801561172657506001600c5f9054906101000a900460ff1660ff16145b80156117565750600160095f8581526020019081526020015f2060010160019054906101000a900460ff1660ff16145b611795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161178c90615396565b60405180910390fd5b5f8260095f8681526020019081526020015f205f01546117b591906159c9565b9050826117c2308661079b565b1015801561186b575080600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b8152600401611829929190615891565b602060405180830381865afa158015611844573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118689190615767565b10155b8015611910575080600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016118ce9190614d09565b602060405180830381865afa1580156118e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190d9190615767565b10155b61194f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194690615396565b60405180910390fd5b61199e333083600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612b2c909392919063ffffffff16565b600160095f8681526020019081526020015f206001015f9054906101000a900460ff1660ff1603611a06576064600a54826119d991906159c9565b6119e39190615a37565b816119ee9190615720565b600b5f8282546119fe9190615792565b925050819055505b611a133086868686612bae565b50611a1c612802565b50505050565b611a2a612633565b611a35308383612cb4565b5050565b5f60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611a73611a6c6128a5565b8383612d56565b5050565b611a7f612633565b60328110158015611a91575060648111155b611ad0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ac790615396565b60405180910390fd5b80600a8190555050565b600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611b08612633565b611b1533858585856121f9565b50505050565b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd3330846040518463ffffffff1660e01b8152600401611b5893929190615a67565b6020604051808303815f875af1158015611b74573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b989190615ab0565b505050565b5f63bc197c8160e01b905098975050505050505050565b5f60045f8381526020019081526020015f20549050919050565b611bd6612633565b5f600267ffffffffffffffff811115611bf257611bf161403b565b5b604051908082528060200260200182016040528015611c205781602001602082028036833780820191505090505b5090505f8260ff1603611e6957600b54600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611c8b9190614d09565b602060405180830381865afa158015611ca6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cca9190615767565b611cd49190615720565b841115611d16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d0d90615396565b60405180910390fd5b611d8460075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815f81518110611dba57611db96153b4565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600d5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681600181518110611e2a57611e296153b4565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050611fb7565b611ed660075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685600d5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b600d5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815f81518110611f0b57611f0a6153b4565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681600181518110611f7c57611f7b6153b4565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338ed173985858430610384426120069190615792565b6040518663ffffffff1660e01b8152600401612026959493929190615b92565b5f604051808303815f875af1158015612041573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906120699190615c7f565b5050505050565b6009602052805f5260405f205f91509050805f015490806001015f9054906101000a900460ff16908060010160019054906101000a900460ff16908060020180546120ba906152bf565b80601f01602080910402602001604051908101604052809291908181526020018280546120e6906152bf565b80156121315780601f1061210857610100808354040283529160200191612131565b820191905f5260205f20905b81548152906001019060200180831161211457829003601f168201915b5050505050905084565b612143612633565b6121503085858585612bae565b50505050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f63f23a6e6160e01b90509695505050505050565b5f6122026128a5565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561224757506122458682612156565b155b1561228b5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401612282929190615891565b60405180910390fd5b6122988686868686612bae565b505050505050565b6122a8612633565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612318575f6040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040161230f9190614d09565b60405180910390fd5b61232181612a69565b50565b61232c6128a5565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561237557506123738361236e6128a5565b612156565b155b156123c0576123826128a5565b836040517fe237d9220000000000000000000000000000000000000000000000000000000081526004016123b7929190615891565b60405180910390fd5b6123cb838383612cb4565b505050565b6123d8612633565b5f8160ff1614806123ec575060018160ff16145b61242b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161242290615396565b60405180910390fd5b8060095f8481526020019081526020015f2060010160016101000a81548160ff021916908360ff1602179055505050565b600c5f9054906101000a900460ff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6060600280546124e6906152bf565b80601f0160208091040260200160405190810160405280929190818152602001828054612512906152bf565b801561255d5780601f106125345761010080835404028352916020019161255d565b820191905f5260205f20905b81548152906001019060200180831161254057829003601f168201915b50505050509050919050565b60605f600161257784612ebf565b0190505f8167ffffffffffffffff8111156125955761259461403b565b5b6040519080825280601f01601f1916602001820160405280156125c75781602001600182028036833780820191505090505b5090505f82602001820190505b600115612628578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161261d5761261c615a0a565b5b0494505f85036125d4575b819350505050919050565b61263b6128a5565b73ffffffffffffffffffffffffffffffffffffffff16612659611a39565b73ffffffffffffffffffffffffffffffffffffffff16146126b85761267c6128a5565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016126af9190614d09565b60405180910390fd5b565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361272a575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016127219190614d09565b60405180910390fd5b6127375f85858585613010565b50505050565b600260065403612779576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600681905550565b6127fd838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016127b6929190615cc6565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506130bc565b505050565b6001600681905550565b5f8373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401612848929190615891565b602060405180830381865afa158015612863573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128879190615767565b905061289f8484848461289a9190615792565b613151565b50505050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361291c575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016129139190614d09565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361298c575f6040517f01a835140000000000000000000000000000000000000000000000000000000081526004016129839190614d09565b60405180910390fd5b6129998585858585613010565b5050505050565b5f60208202602084010151905092915050565b5f60208202602084010151905092915050565b80600290816129d591906155dd565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612a49575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401612a409190614d09565b60405180910390fd5b612a64835f848460405180602001604052805f815250613010565b505050565b5f60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160035f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b612ba8848573ffffffffffffffffffffffffffffffffffffffff166323b872dd868686604051602401612b6193929190615a67565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506130bc565b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612c1e575f6040517f57f447ce000000000000000000000000000000000000000000000000000000008152600401612c159190614d09565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612c8e575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401612c859190614d09565b60405180910390fd5b5f80612c9a858561325e565b91509150612cab8787848487613010565b50505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612d24575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401612d1b9190614d09565b60405180910390fd5b5f80612d30848461325e565b91509150612d4f855f848460405180602001604052805f815250613010565b5050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612dc6575f6040517fced3e100000000000000000000000000000000000000000000000000000000008152600401612dbd9190614d09565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051612eb29190613f49565b60405180910390a3505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612f1b577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381612f1157612f10615a0a565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612f58576d04ee2d6d415b85acef81000000008381612f4e57612f4d615a0a565b5b0492506020810190505b662386f26fc100008310612f8757662386f26fc100008381612f7d57612f7c615a0a565b5b0492506010810190505b6305f5e1008310612fb0576305f5e1008381612fa657612fa5615a0a565b5b0492506008810190505b6127108310612fd5576127108381612fcb57612fca615a0a565b5b0492506004810190505b60648310612ff85760648381612fee57612fed615a0a565b5b0492506002810190505b600a8310613007576001810190505b80915050919050565b61301c8585858561328e565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146130b5575f6130586128a5565b905060018451036130a4575f6130775f866129b390919063ffffffff16565b90505f61308d5f866129b390919063ffffffff16565b905061309d8389898585896132a0565b50506130b3565b6130b281878787878761344f565b5b505b5050505050565b5f6130e6828473ffffffffffffffffffffffffffffffffffffffff166135fe90919063ffffffff16565b90505f81511415801561310a5750808060200190518101906131089190615ab0565b155b1561314c57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016131439190614d09565b60405180910390fd5b505050565b5f8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b38484604051602401613181929190615cc6565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506131cf8482613613565b6132585761324d848573ffffffffffffffffffffffffffffffffffffffff1663095ea7b3865f604051602401613206929190615d26565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506130bc565b61325784826130bc565b5b50505050565b60608060405191506001825283602083015260408201905060018152826020820152604081016040529250929050565b61329a848484846136d2565b50505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115613447578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401613300959493929190615d9f565b6020604051808303815f875af192505050801561333b57506040513d601f19601f820116820180604052508101906133389190615e0b565b60015b6133bc573d805f8114613369576040519150601f19603f3d011682016040523d82523d5f602084013e61336e565b606091505b505f8151036133b457846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016133ab9190614d09565b60405180910390fd5b805181602001fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461344557846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161343c9190614d09565b60405180910390fd5b505b505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b11156135f6578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b81526004016134af959493929190615e36565b6020604051808303815f875af19250505080156134ea57506040513d601f19601f820116820180604052508101906134e79190615e0b565b60015b61356b573d805f8114613518576040519150601f19603f3d011682016040523d82523d5f602084013e61351d565b606091505b505f81510361356357846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161355a9190614d09565b60405180910390fd5b805181602001fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146135f457846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016135eb9190614d09565b60405180910390fd5b505b505050505050565b606061360b83835f61387b565b905092915050565b5f805f8473ffffffffffffffffffffffffffffffffffffffff168460405161363b9190615ed6565b5f604051808303815f865af19150503d805f8114613674576040519150601f19603f3d011682016040523d82523d5f602084013e613679565b606091505b50915091508180156136a657505f815114806136a55750808060200190518101906136a49190615ab0565b5b5b80156136c857505f8573ffffffffffffffffffffffffffffffffffffffff163b115b9250505092915050565b6136de84848484613944565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036137b7575f805b835181101561379c575f838281518110613731576137306153b4565b5b602002602001015190508060045f878581518110613752576137516153b4565b5b602002602001015181526020019081526020015f205f8282546137759190615792565b9250508190555080836137889190615792565b92505080613795906156d9565b9050613714565b508060055f8282546137ae9190615792565b92505081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613875575f805b8351811015613863575f83828151811061380a576138096153b4565b5b602002602001015190508060045f87858151811061382b5761382a6153b4565b5b602002602001015181526020019081526020015f205f82825403925050819055508083019250508061385c906156d9565b90506137ed565b508060055f8282540392505081905550505b50505050565b6060814710156138c257306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016138b99190614d09565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516138ea9190615ed6565b5f6040518083038185875af1925050503d805f8114613924576040519150601f19603f3d011682016040523d82523d5f602084013e613929565b606091505b5091509150613939868383613cda565b925050509392505050565b805182511461398e57815181516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016139859291906158b8565b60405180910390fd5b5f6139976128a5565b90505f5b8351811015613b99575f6139b882866129b390919063ffffffff16565b90505f6139ce83866129b390919063ffffffff16565b90505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614613af1575f805f8481526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015613a9d57888183856040517f03dee4c5000000000000000000000000000000000000000000000000000000008152600401613a949493929190615eec565b60405180910390fd5b8181035f808581526020019081526020015f205f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614613b8657805f808481526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254613b7e9190615792565b925050819055505b505080613b92906156d9565b905061399b565b506001835103613c54575f613bb75f856129b390919063ffffffff16565b90505f613bcd5f856129b390919063ffffffff16565b90508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051613c459291906158b8565b60405180910390a45050613cd3565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051613cca929190615f2f565b60405180910390a45b5050505050565b606082613cef57613cea82613d67565b613d5f565b5f8251148015613d1557505f8473ffffffffffffffffffffffffffffffffffffffff163b145b15613d5757836040517f9996b315000000000000000000000000000000000000000000000000000000008152600401613d4e9190614d09565b60405180910390fd5b819050613d60565b5b9392505050565b5f81511115613d795780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613de582613dbc565b9050919050565b613df581613ddb565b8114613dff575f80fd5b50565b5f81359050613e1081613dec565b92915050565b5f819050919050565b613e2881613e16565b8114613e32575f80fd5b50565b5f81359050613e4381613e1f565b92915050565b5f8060408385031215613e5f57613e5e613db4565b5b5f613e6c85828601613e02565b9250506020613e7d85828601613e35565b9150509250929050565b613e9081613e16565b82525050565b5f602082019050613ea95f830184613e87565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ee381613eaf565b8114613eed575f80fd5b50565b5f81359050613efe81613eda565b92915050565b5f60208284031215613f1957613f18613db4565b5b5f613f2684828501613ef0565b91505092915050565b5f8115159050919050565b613f4381613f2f565b82525050565b5f602082019050613f5c5f830184613f3a565b92915050565b5f60208284031215613f7757613f76613db4565b5b5f613f8484828501613e35565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015613fc4578082015181840152602081019050613fa9565b5f8484015250505050565b5f601f19601f8301169050919050565b5f613fe982613f8d565b613ff38185613f97565b9350614003818560208601613fa7565b61400c81613fcf565b840191505092915050565b5f6020820190508181035f83015261402f8184613fdf565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61407182613fcf565b810181811067ffffffffffffffff821117156140905761408f61403b565b5b80604052505050565b5f6140a2613dab565b90506140ae8282614068565b919050565b5f67ffffffffffffffff8211156140cd576140cc61403b565b5b602082029050602081019050919050565b5f80fd5b5f6140f46140ef846140b3565b614099565b90508083825260208201905060208402830185811115614117576141166140de565b5b835b81811015614140578061412c8882613e35565b845260208401935050602081019050614119565b5050509392505050565b5f82601f83011261415e5761415d614037565b5b813561416e8482602086016140e2565b91505092915050565b5f67ffffffffffffffff8211156141915761419061403b565b5b602082029050602081019050919050565b5f80fd5b5f67ffffffffffffffff8211156141c0576141bf61403b565b5b6141c982613fcf565b9050602081019050919050565b828183375f83830152505050565b5f6141f66141f1846141a6565b614099565b905082815260208101848484011115614212576142116141a2565b5b61421d8482856141d6565b509392505050565b5f82601f83011261423957614238614037565b5b81356142498482602086016141e4565b91505092915050565b5f61426461425f84614177565b614099565b90508083825260208201905060208402830185811115614287576142866140de565b5b835b818110156142ce57803567ffffffffffffffff8111156142ac576142ab614037565b5b8086016142b98982614225565b85526020850194505050602081019050614289565b5050509392505050565b5f82601f8301126142ec576142eb614037565b5b81356142fc848260208601614252565b91505092915050565b5f67ffffffffffffffff82111561431f5761431e61403b565b5b602082029050602081019050919050565b5f60ff82169050919050565b61434581614330565b811461434f575f80fd5b50565b5f813590506143608161433c565b92915050565b5f61437861437384614305565b614099565b9050808382526020820190506020840283018581111561439b5761439a6140de565b5b835b818110156143c457806143b08882614352565b84526020840193505060208101905061439d565b5050509392505050565b5f82601f8301126143e2576143e1614037565b5b81356143f2848260208601614366565b91505092915050565b5f67ffffffffffffffff8211156144155761441461403b565b5b61441e82613fcf565b9050602081019050919050565b5f61443d614438846143fb565b614099565b905082815260208101848484011115614459576144586141a2565b5b6144648482856141d6565b509392505050565b5f82601f8301126144805761447f614037565b5b813561449084826020860161442b565b91505092915050565b5f805f805f805f80610100898b0312156144b6576144b5613db4565b5b5f6144c38b828c01613e02565b985050602089013567ffffffffffffffff8111156144e4576144e3613db8565b5b6144f08b828c0161414a565b975050604089013567ffffffffffffffff81111561451157614510613db8565b5b61451d8b828c0161414a565b965050606089013567ffffffffffffffff81111561453e5761453d613db8565b5b61454a8b828c016142d8565b955050608089013567ffffffffffffffff81111561456b5761456a613db8565b5b6145778b828c0161414a565b94505060a089013567ffffffffffffffff81111561459857614597613db8565b5b6145a48b828c016143ce565b93505060c089013567ffffffffffffffff8111156145c5576145c4613db8565b5b6145d18b828c016143ce565b92505060e089013567ffffffffffffffff8111156145f2576145f1613db8565b5b6145fe8b828c0161446c565b9150509295985092959890939650565b5f819050919050565b5f61463161462c61462784613dbc565b61460e565b613dbc565b9050919050565b5f61464282614617565b9050919050565b5f61465382614638565b9050919050565b61466381614649565b82525050565b5f60208201905061467c5f83018461465a565b92915050565b5f805f805f8060c0878903121561469c5761469b613db4565b5b5f6146a989828a01613e02565b96505060206146ba89828a01613e02565b95505060406146cb89828a01613e35565b94505060606146dc89828a01613e35565b93505060806146ed89828a01613e35565b92505060a06146fe89828a01613e35565b9150509295509295509295565b5f805f805f60a0868803121561472457614723613db4565b5b5f61473188828901613e02565b955050602061474288828901613e02565b945050604086013567ffffffffffffffff81111561476357614762613db8565b5b61476f8882890161414a565b935050606086013567ffffffffffffffff8111156147905761478f613db8565b5b61479c8882890161414a565b925050608086013567ffffffffffffffff8111156147bd576147bc613db8565b5b6147c98882890161446c565b9150509295509295909350565b5f6147e082614638565b9050919050565b6147f0816147d6565b82525050565b5f6020820190506148095f8301846147e7565b92915050565b5f6020828403121561482457614823613db4565b5b5f61483184828501614352565b91505092915050565b5f80604083850312156148505761484f613db4565b5b5f83013567ffffffffffffffff81111561486d5761486c613db8565b5b6148798582860161414a565b925050602083013567ffffffffffffffff81111561489a57614899613db8565b5b6148a6858286016142d8565b9150509250929050565b5f67ffffffffffffffff8211156148ca576148c961403b565b5b602082029050602081019050919050565b5f6148ed6148e8846148b0565b614099565b905080838252602082019050602084028301858111156149105761490f6140de565b5b835b8181101561493957806149258882613e02565b845260208401935050602081019050614912565b5050509392505050565b5f82601f83011261495757614956614037565b5b81356149678482602086016148db565b91505092915050565b5f806040838503121561498657614985613db4565b5b5f83013567ffffffffffffffff8111156149a3576149a2613db8565b5b6149af85828601614943565b925050602083013567ffffffffffffffff8111156149d0576149cf613db8565b5b6149dc8582860161414a565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b614a1881613e16565b82525050565b5f614a298383614a0f565b60208301905092915050565b5f602082019050919050565b5f614a4b826149e6565b614a5581856149f0565b9350614a6083614a00565b805f5b83811015614a90578151614a778882614a1e565b9750614a8283614a35565b925050600181019050614a63565b5085935050505092915050565b5f6020820190508181035f830152614ab58184614a41565b905092915050565b5f60208284031215614ad257614ad1613db4565b5b5f82013567ffffffffffffffff811115614aef57614aee613db8565b5b614afb84828501614225565b91505092915050565b5f614b0e82614638565b9050919050565b614b1e81614b04565b82525050565b5f602082019050614b375f830184614b15565b92915050565b5f805f60608486031215614b5457614b53613db4565b5b5f614b6186828701613e02565b935050602084013567ffffffffffffffff811115614b8257614b81613db8565b5b614b8e8682870161414a565b925050604084013567ffffffffffffffff811115614baf57614bae613db8565b5b614bbb8682870161414a565b9150509250925092565b5f805f805f60a08688031215614bde57614bdd613db4565b5b5f614beb88828901613e02565b9550506020614bfc88828901613e02565b9450506040614c0d88828901613e35565b9350506060614c1e88828901613e35565b9250506080614c2f88828901613e35565b9150509295509295909350565b5f805f8060808587031215614c5457614c53613db4565b5b5f614c6187828801613e02565b9450506020614c7287828801613e35565b9350506040614c8387828801613e35565b925050606085013567ffffffffffffffff811115614ca457614ca3613db8565b5b614cb08782880161446c565b91505092959194509250565b5f8060408385031215614cd257614cd1613db4565b5b5f614cdf85828601613e35565b9250506020614cf085828601613e35565b9150509250929050565b614d0381613ddb565b82525050565b5f602082019050614d1c5f830184614cfa565b92915050565b614d2b81613f2f565b8114614d35575f80fd5b50565b5f81359050614d4681614d22565b92915050565b5f8060408385031215614d6257614d61613db4565b5b5f614d6f85828601613e02565b9250506020614d8085828601614d38565b9150509250929050565b5f614d9482613ddb565b9050919050565b614da481614d8a565b8114614dae575f80fd5b50565b5f81359050614dbf81614d9b565b92915050565b5f8060408385031215614ddb57614dda613db4565b5b5f614de885828601614db1565b9250506020614df985828601613e35565b9150509250929050565b5f80fd5b5f8083601f840112614e1c57614e1b614037565b5b8235905067ffffffffffffffff811115614e3957614e38614e03565b5b602083019150836020820283011115614e5557614e546140de565b5b9250929050565b5f8083601f840112614e7157614e70614037565b5b8235905067ffffffffffffffff811115614e8e57614e8d614e03565b5b602083019150836001820283011115614eaa57614ea96140de565b5b9250929050565b5f805f805f805f8060a0898b031215614ecd57614ecc613db4565b5b5f614eda8b828c01613e02565b9850506020614eeb8b828c01613e02565b975050604089013567ffffffffffffffff811115614f0c57614f0b613db8565b5b614f188b828c01614e07565b9650965050606089013567ffffffffffffffff811115614f3b57614f3a613db8565b5b614f478b828c01614e07565b9450945050608089013567ffffffffffffffff811115614f6a57614f69613db8565b5b614f768b828c01614e5c565b92509250509295985092959890939650565b614f9181613eaf565b82525050565b5f602082019050614faa5f830184614f88565b92915050565b5f805f60608486031215614fc757614fc6613db4565b5b5f614fd486828701613e35565b9350506020614fe586828701613e35565b9250506040614ff686828701614352565b9150509250925092565b61500981614330565b82525050565b5f6080820190506150225f830187613e87565b61502f6020830186615000565b61503c6040830185615000565b818103606083015261504e8184613fdf565b905095945050505050565b5f806040838503121561506f5761506e613db4565b5b5f61507c85828601613e02565b925050602061508d85828601613e02565b9150509250929050565b5f805f805f8060a087890312156150b1576150b0613db4565b5b5f6150be89828a01613e02565b96505060206150cf89828a01613e02565b95505060406150e089828a01613e35565b94505060606150f189828a01613e35565b935050608087013567ffffffffffffffff81111561511257615111613db8565b5b61511e89828a01614e5c565b92509250509295509295509295565b5f805f805f60a0868803121561514657615145613db4565b5b5f61515388828901613e02565b955050602061516488828901613e02565b945050604061517588828901613e35565b935050606061518688828901613e35565b925050608086013567ffffffffffffffff8111156151a7576151a6613db8565b5b6151b38882890161446c565b9150509295509295909350565b5f602082840312156151d5576151d4613db4565b5b5f6151e284828501613e02565b91505092915050565b5f805f6060848603121561520257615201613db4565b5b5f61520f86828701613e02565b935050602061522086828701613e35565b925050604061523186828701613e35565b9150509250925092565b5f806040838503121561525157615250613db4565b5b5f61525e85828601613e35565b925050602061526f85828601614352565b9150509250929050565b5f60208201905061528c5f830184615000565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806152d657607f821691505b6020821081036152e9576152e8615292565b5b50919050565b5f81905092915050565b5f61530382613f8d565b61530d81856152ef565b935061531d818560208601613fa7565b80840191505092915050565b5f61533482856152f9565b915061534082846152f9565b91508190509392505050565b7f496e76616c6964207265717565737400000000000000000000000000000000005f82015250565b5f615380600f83613f97565b915061538b8261534c565b602082019050919050565b5f6020820190508181035f8301526153ad81615374565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f546f6b656e20494420616c7265616479206578697374730000000000000000005f82015250565b5f615415601783613f97565b9150615420826153e1565b602082019050919050565b5f6020820190508181035f83015261544281615409565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026154a57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8261546a565b6154af868361546a565b95508019841693508086168417925050509392505050565b5f6154e16154dc6154d784613e16565b61460e565b613e16565b9050919050565b5f819050919050565b6154fa836154c7565b61550e615506826154e8565b848454615476565b825550505050565b5f90565b615522615516565b61552d8184846154f1565b505050565b5b81811015615550576155455f8261551a565b600181019050615533565b5050565b601f8211156155955761556681615449565b61556f8461545b565b8101602085101561557e578190505b61559261558a8561545b565b830182615532565b50505b505050565b5f82821c905092915050565b5f6155b55f198460080261559a565b1980831691505092915050565b5f6155cd83836155a6565b9150826002028217905092915050565b6155e682613f8d565b67ffffffffffffffff8111156155ff576155fe61403b565b5b61560982546152bf565b615614828285615554565b5f60209050601f831160018114615645575f8415615633578287015190505b61563d85826155c2565b8655506156a4565b601f19841661565386615449565b5f5b8281101561567a57848901518255600182019150602085019450602081019050615655565b868310156156975784890151615693601f8916826155a6565b8355505b6001600288020188555050505b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6156e382613e16565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615715576157146156ac565b5b600182019050919050565b5f61572a82613e16565b915061573583613e16565b925082820390508181111561574d5761574c6156ac565b5b92915050565b5f8151905061576181613e1f565b92915050565b5f6020828403121561577c5761577b613db4565b5b5f61578984828501615753565b91505092915050565b5f61579c82613e16565b91506157a783613e16565b92508282019050808211156157bf576157be6156ac565b5b92915050565b5f610100820190506157d95f83018b614cfa565b6157e6602083018a614cfa565b6157f36040830189613e87565b6158006060830188613e87565b61580d6080830187613e87565b61581a60a0830186613e87565b61582760c0830185614cfa565b61583460e0830184613e87565b9998505050505050505050565b5f805f6060848603121561585857615857613db4565b5b5f61586586828701615753565b935050602061587686828701615753565b925050604061588786828701615753565b9150509250925092565b5f6040820190506158a45f830185614cfa565b6158b16020830184614cfa565b9392505050565b5f6040820190506158cb5f830185613e87565b6158d86020830184613e87565b9392505050565b5f815190506158ed81613dec565b92915050565b5f6020828403121561590857615907613db4565b5b5f615915848285016158df565b91505092915050565b5f60e0820190506159315f83018a614cfa565b61593e6020830189614cfa565b61594b6040830188613e87565b6159586060830187613e87565b6159656080830186613e87565b61597260a0830185614cfa565b61597f60c0830184613e87565b98975050505050505050565b5f80604083850312156159a1576159a0613db4565b5b5f6159ae85828601615753565b92505060206159bf85828601615753565b9150509250929050565b5f6159d382613e16565b91506159de83613e16565b92508282026159ec81613e16565b91508282048414831517615a0357615a026156ac565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f615a4182613e16565b9150615a4c83613e16565b925082615a5c57615a5b615a0a565b5b828204905092915050565b5f606082019050615a7a5f830186614cfa565b615a876020830185614cfa565b615a946040830184613e87565b949350505050565b5f81519050615aaa81614d22565b92915050565b5f60208284031215615ac557615ac4613db4565b5b5f615ad284828501615a9c565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b615b0d81613ddb565b82525050565b5f615b1e8383615b04565b60208301905092915050565b5f602082019050919050565b5f615b4082615adb565b615b4a8185615ae5565b9350615b5583615af5565b805f5b83811015615b85578151615b6c8882615b13565b9750615b7783615b2a565b925050600181019050615b58565b5085935050505092915050565b5f60a082019050615ba55f830188613e87565b615bb26020830187613e87565b8181036040830152615bc48186615b36565b9050615bd36060830185614cfa565b615be06080830184613e87565b9695505050505050565b5f615bfc615bf7846140b3565b614099565b90508083825260208201905060208402830185811115615c1f57615c1e6140de565b5b835b81811015615c485780615c348882615753565b845260208401935050602081019050615c21565b5050509392505050565b5f82601f830112615c6657615c65614037565b5b8151615c76848260208601615bea565b91505092915050565b5f60208284031215615c9457615c93613db4565b5b5f82015167ffffffffffffffff811115615cb157615cb0613db8565b5b615cbd84828501615c52565b91505092915050565b5f604082019050615cd95f830185614cfa565b615ce66020830184613e87565b9392505050565b5f819050919050565b5f615d10615d0b615d0684615ced565b61460e565b613e16565b9050919050565b615d2081615cf6565b82525050565b5f604082019050615d395f830185614cfa565b615d466020830184615d17565b9392505050565b5f81519050919050565b5f82825260208201905092915050565b5f615d7182615d4d565b615d7b8185615d57565b9350615d8b818560208601613fa7565b615d9481613fcf565b840191505092915050565b5f60a082019050615db25f830188614cfa565b615dbf6020830187614cfa565b615dcc6040830186613e87565b615dd96060830185613e87565b8181036080830152615deb8184615d67565b90509695505050505050565b5f81519050615e0581613eda565b92915050565b5f60208284031215615e2057615e1f613db4565b5b5f615e2d84828501615df7565b91505092915050565b5f60a082019050615e495f830188614cfa565b615e566020830187614cfa565b8181036040830152615e688186614a41565b90508181036060830152615e7c8185614a41565b90508181036080830152615e908184615d67565b90509695505050505050565b5f81905092915050565b5f615eb082615d4d565b615eba8185615e9c565b9350615eca818560208601613fa7565b80840191505092915050565b5f615ee18284615ea6565b915081905092915050565b5f608082019050615eff5f830187614cfa565b615f0c6020830186613e87565b615f196040830185613e87565b615f266060830184613e87565b95945050505050565b5f6040820190508181035f830152615f478185614a41565b90508181036020830152615f5b8184614a41565b9050939250505056fea264697066735822122051efa173c94ef6b52f8eb5e62dcf4be19b02bd8a285c990213930cb047bdb76964736f6c634300081400330000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000088ee7a3537667958d040216d9dc1752d1274d838

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610250575f3560e01c8063715018a611610144578063bd85b039116100c1578063f23a6e6111610085578063f23a6e61146106dd578063f242432a1461070d578063f2fde38b14610729578063f5298aca14610745578063f807427d14610761578063f9020e331461077d57610250565b8063bd85b03914610612578063c4d32bf314610642578063cc33c8751461065e578063cf8ca74114610691578063e985e9c5146106ad57610250565b8063a8275ada11610108578063a8275ada14610570578063a98ad46c1461058c578063ae28b68c146105aa578063aed4aab6146105c6578063bc197c81146105e257610250565b8063715018a6146104f457806386f5c0d8146104fe5780638d8a818c1461051a5780638da5cb5b14610536578063a22cb4651461055457610250565b80633d54353a116101d25780634f558e79116101965780634f558e791461045257806355f804b31461048257806359d0f7131461049e5780636b20c454146104bc5780636b421a50146104d857610250565b80633d54353a146103ae5780633e7e30ba146103cc5780634891ad88146103ea5780634bb99351146104065780634e1273f41461042257610250565b80631694505e116102195780631694505e1461031c57806318160ddd1461033a5780632e6ceabe146103585780632eb2c2d61461037457806334b633ce1461039057610250565b8062fdd58e1461025457806301ffc9a7146102845780630e89341c146102b457806312d6f800146102e45780631481794e14610300575b5f80fd5b61026e60048036038101906102699190613e49565b61079b565b60405161027b9190613e96565b60405180910390f35b61029e60048036038101906102999190613f04565b6107f0565b6040516102ab9190613f49565b60405180910390f35b6102ce60048036038101906102c99190613f62565b6108d1565b6040516102db9190614017565b60405180910390f35b6102fe60048036038101906102f99190614499565b6109e0565b005b61031a60048036038101906103159190613e49565b610c14565b005b610324610d12565b6040516103319190614669565b60405180910390f35b610342610d37565b60405161034f9190613e96565b60405180910390f35b610372600480360381019061036d9190614682565b610d40565b005b61038e6004803603810190610389919061470b565b61107d565b005b610398611124565b6040516103a59190613e96565b60405180910390f35b6103b661112a565b6040516103c391906147f6565b60405180910390f35b6103d461114f565b6040516103e19190613e96565b60405180910390f35b61040460048036038101906103ff919061480f565b611155565b005b610420600480360381019061041b919061483a565b6111cd565b005b61043c60048036038101906104379190614970565b611292565b6040516104499190614a9d565b60405180910390f35b61046c60048036038101906104679190613f62565b61139f565b6040516104799190613f49565b60405180910390f35b61049c60048036038101906104979190614abd565b6113b2565b005b6104a66113c6565b6040516104b39190614b24565b60405180910390f35b6104d660048036038101906104d19190614b3d565b6113eb565b005b6104f260048036038101906104ed9190614bc5565b611497565b005b6104fc6116b3565b005b61051860048036038101906105139190614c3c565b6116c6565b005b610534600480360381019061052f9190614cbc565b611a22565b005b61053e611a39565b60405161054b9190614d09565b60405180910390f35b61056e60048036038101906105699190614d4c565b611a61565b005b61058a60048036038101906105859190613f62565b611a77565b005b610594611ada565b6040516105a191906147f6565b60405180910390f35b6105c460048036038101906105bf9190614c3c565b611b00565b005b6105e060048036038101906105db9190614dc5565b611b1b565b005b6105fc60048036038101906105f79190614eb1565b611b9d565b6040516106099190614f97565b60405180910390f35b61062c60048036038101906106279190613f62565b611bb4565b6040516106399190613e96565b60405180910390f35b61065c60048036038101906106579190614fb0565b611bce565b005b61067860048036038101906106739190613f62565b612070565b604051610688949392919061500f565b60405180910390f35b6106ab60048036038101906106a69190614c3c565b61213b565b005b6106c760048036038101906106c29190615059565b612156565b6040516106d49190613f49565b60405180910390f35b6106f760048036038101906106f29190615097565b6121e4565b6040516107049190614f97565b60405180910390f35b6107276004803603810190610722919061512d565b6121f9565b005b610743600480360381019061073e91906151c0565b6122a0565b005b61075f600480360381019061075a91906151eb565b612324565b005b61077b6004803603810190610776919061523b565b6123d0565b005b61078561245c565b6040516107929190615279565b60405180910390f35b5f805f8381526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f7fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806108ba57507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108ca57506108c98261246e565b5b9050919050565b60605f60095f8481526020019081526020015f2060020180546108f3906152bf565b80601f016020809104026020016040519081016040528092919081815260200182805461091f906152bf565b801561096a5780601f106109415761010080835404028352916020019161096a565b820191905f5260205f20905b81548152906001019060200180831161094d57829003601f168201915b505050505090505f61097b846124d7565b90505f8251116109b4578061098f85612569565b6040516020016109a0929190615329565b6040516020818303038152906040526109d7565b80826040516020016109c7929190615329565b6040516020818303038152906040525b92505050919050565b6109e8612633565b855187511480156109fa575084518751145b8015610a07575083518751145b8015610a14575082518751145b8015610a21575081518751145b610a60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5790615396565b60405180910390fd5b5f5b8751811015610bfd57610a8e888281518110610a8157610a806153b4565b5b602002602001015161139f565b15610ace576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ac59061542b565b60405180910390fd5b6040518060800160405280868381518110610aec57610aeb6153b4565b5b60200260200101518152602001858381518110610b0c57610b0b6153b4565b5b602002602001015160ff168152602001848381518110610b2f57610b2e6153b4565b5b602002602001015160ff168152602001878381518110610b5257610b516153b4565b5b602002602001015181525060095f8a8481518110610b7357610b726153b4565b5b602002602001015181526020019081526020015f205f820151815f01556020820151816001015f6101000a81548160ff021916908360ff16021790555060408201518160010160016101000a81548160ff021916908360ff1602179055506060820151816002019081610be691906155dd565b509050508080610bf5906156d9565b915050610a62565b50610c0a888888846126ba565b5050505050505050565b610c1c612633565b610c2461273d565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610c625750600b548111155b610ca1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9890615396565b60405180910390fd5b80600b5f828254610cb29190615720565b92505081905550610d068282600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166127839092919063ffffffff16565b610d0e612802565b5050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f600554905090565b610d48612633565b5f600b54600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610da79190614d09565b602060405180830381865afa158015610dc2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610de69190615767565b610df09190615720565b9050600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603610e8b5780851115610e8a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e8190615396565b60405180910390fd5b5b600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603610f245780841115610f23576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1a90615396565b60405180910390fd5b5b610f7060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16868973ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b610fbc60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16858873ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e8e33700888888888888306103844261100e9190615792565b6040518963ffffffff1660e01b81526004016110319897969594939291906157c5565b6060604051808303815f875af115801561104d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110719190615841565b50505050505050505050565b5f6110866128a5565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580156110cb57506110c98682612156565b155b1561110f5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401611106929190615891565b60405180910390fd5b61111c86868686866128ac565b505050505050565b600b5481565b600d5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600a5481565b61115d612633565b5f8160ff161480611171575060018160ff16145b6111b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111a790615396565b60405180910390fd5b80600c5f6101000a81548160ff021916908360ff16021790555050565b6111d5612633565b8051825114611219576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121090615396565b60405180910390fd5b5f5b825181101561128d57818181518110611237576112366153b4565b5b602002602001015160095f858481518110611255576112546153b4565b5b602002602001015181526020019081526020015f20600201908161127991906155dd565b508080611285906156d9565b91505061121b565b505050565b606081518351146112de57815183516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016112d59291906158b8565b60405180910390fd5b5f835167ffffffffffffffff8111156112fa576112f961403b565b5b6040519080825280602002602001820160405280156113285781602001602082028036833780820191505090505b5090505f5b84518110156113945761136461134c82876129a090919063ffffffff16565b61135f83876129b390919063ffffffff16565b61079b565b828281518110611377576113766153b4565b5b6020026020010181815250508061138d906156d9565b905061132d565b508091505092915050565b5f806113aa83611bb4565b119050919050565b6113ba612633565b6113c3816129c6565b50565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6113f36128a5565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561143c575061143a836114356128a5565b612156565b155b15611487576114496128a5565b836040517fe237d92200000000000000000000000000000000000000000000000000000000815260040161147e929190615891565b60405180910390fd5b6114928383836129d9565b505050565b61149f612633565b5f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e6a4390587876040518363ffffffff1660e01b81526004016114fc929190615891565b602060405180830381865afa158015611517573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061153b91906158f3565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036115ab576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115a290615396565b60405180910390fd5b6115f760075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16858373ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663baa2abde878787878730610384426116489190615792565b6040518863ffffffff1660e01b815260040161166a979695949392919061591e565b60408051808303815f875af1158015611685573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116a9919061598b565b5050505050505050565b6116bb612633565b6116c45f612a69565b565b6116ce61273d565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415801561170957505f82115b801561172657506001600c5f9054906101000a900460ff1660ff16145b80156117565750600160095f8581526020019081526020015f2060010160019054906101000a900460ff1660ff16145b611795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161178c90615396565b60405180910390fd5b5f8260095f8681526020019081526020015f205f01546117b591906159c9565b9050826117c2308661079b565b1015801561186b575080600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b8152600401611829929190615891565b602060405180830381865afa158015611844573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118689190615767565b10155b8015611910575080600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016118ce9190614d09565b602060405180830381865afa1580156118e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190d9190615767565b10155b61194f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194690615396565b60405180910390fd5b61199e333083600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612b2c909392919063ffffffff16565b600160095f8681526020019081526020015f206001015f9054906101000a900460ff1660ff1603611a06576064600a54826119d991906159c9565b6119e39190615a37565b816119ee9190615720565b600b5f8282546119fe9190615792565b925050819055505b611a133086868686612bae565b50611a1c612802565b50505050565b611a2a612633565b611a35308383612cb4565b5050565b5f60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611a73611a6c6128a5565b8383612d56565b5050565b611a7f612633565b60328110158015611a91575060648111155b611ad0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ac790615396565b60405180910390fd5b80600a8190555050565b600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611b08612633565b611b1533858585856121f9565b50505050565b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd3330846040518463ffffffff1660e01b8152600401611b5893929190615a67565b6020604051808303815f875af1158015611b74573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b989190615ab0565b505050565b5f63bc197c8160e01b905098975050505050505050565b5f60045f8381526020019081526020015f20549050919050565b611bd6612633565b5f600267ffffffffffffffff811115611bf257611bf161403b565b5b604051908082528060200260200182016040528015611c205781602001602082028036833780820191505090505b5090505f8260ff1603611e6957600b54600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611c8b9190614d09565b602060405180830381865afa158015611ca6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cca9190615767565b611cd49190615720565b841115611d16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d0d90615396565b60405180910390fd5b611d8460075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815f81518110611dba57611db96153b4565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600d5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681600181518110611e2a57611e296153b4565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050611fb7565b611ed660075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685600d5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661280c9092919063ffffffff16565b600d5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815f81518110611f0b57611f0a6153b4565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600c60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681600181518110611f7c57611f7b6153b4565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338ed173985858430610384426120069190615792565b6040518663ffffffff1660e01b8152600401612026959493929190615b92565b5f604051808303815f875af1158015612041573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906120699190615c7f565b5050505050565b6009602052805f5260405f205f91509050805f015490806001015f9054906101000a900460ff16908060010160019054906101000a900460ff16908060020180546120ba906152bf565b80601f01602080910402602001604051908101604052809291908181526020018280546120e6906152bf565b80156121315780601f1061210857610100808354040283529160200191612131565b820191905f5260205f20905b81548152906001019060200180831161211457829003601f168201915b5050505050905084565b612143612633565b6121503085858585612bae565b50505050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f63f23a6e6160e01b90509695505050505050565b5f6122026128a5565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561224757506122458682612156565b155b1561228b5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401612282929190615891565b60405180910390fd5b6122988686868686612bae565b505050505050565b6122a8612633565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612318575f6040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040161230f9190614d09565b60405180910390fd5b61232181612a69565b50565b61232c6128a5565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561237557506123738361236e6128a5565b612156565b155b156123c0576123826128a5565b836040517fe237d9220000000000000000000000000000000000000000000000000000000081526004016123b7929190615891565b60405180910390fd5b6123cb838383612cb4565b505050565b6123d8612633565b5f8160ff1614806123ec575060018160ff16145b61242b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161242290615396565b60405180910390fd5b8060095f8481526020019081526020015f2060010160016101000a81548160ff021916908360ff1602179055505050565b600c5f9054906101000a900460ff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6060600280546124e6906152bf565b80601f0160208091040260200160405190810160405280929190818152602001828054612512906152bf565b801561255d5780601f106125345761010080835404028352916020019161255d565b820191905f5260205f20905b81548152906001019060200180831161254057829003601f168201915b50505050509050919050565b60605f600161257784612ebf565b0190505f8167ffffffffffffffff8111156125955761259461403b565b5b6040519080825280601f01601f1916602001820160405280156125c75781602001600182028036833780820191505090505b5090505f82602001820190505b600115612628578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161261d5761261c615a0a565b5b0494505f85036125d4575b819350505050919050565b61263b6128a5565b73ffffffffffffffffffffffffffffffffffffffff16612659611a39565b73ffffffffffffffffffffffffffffffffffffffff16146126b85761267c6128a5565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016126af9190614d09565b60405180910390fd5b565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361272a575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016127219190614d09565b60405180910390fd5b6127375f85858585613010565b50505050565b600260065403612779576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600681905550565b6127fd838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016127b6929190615cc6565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506130bc565b505050565b6001600681905550565b5f8373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401612848929190615891565b602060405180830381865afa158015612863573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128879190615767565b905061289f8484848461289a9190615792565b613151565b50505050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361291c575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016129139190614d09565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361298c575f6040517f01a835140000000000000000000000000000000000000000000000000000000081526004016129839190614d09565b60405180910390fd5b6129998585858585613010565b5050505050565b5f60208202602084010151905092915050565b5f60208202602084010151905092915050565b80600290816129d591906155dd565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612a49575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401612a409190614d09565b60405180910390fd5b612a64835f848460405180602001604052805f815250613010565b505050565b5f60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160035f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b612ba8848573ffffffffffffffffffffffffffffffffffffffff166323b872dd868686604051602401612b6193929190615a67565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506130bc565b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612c1e575f6040517f57f447ce000000000000000000000000000000000000000000000000000000008152600401612c159190614d09565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612c8e575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401612c859190614d09565b60405180910390fd5b5f80612c9a858561325e565b91509150612cab8787848487613010565b50505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612d24575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401612d1b9190614d09565b60405180910390fd5b5f80612d30848461325e565b91509150612d4f855f848460405180602001604052805f815250613010565b5050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612dc6575f6040517fced3e100000000000000000000000000000000000000000000000000000000008152600401612dbd9190614d09565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051612eb29190613f49565b60405180910390a3505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612f1b577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381612f1157612f10615a0a565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612f58576d04ee2d6d415b85acef81000000008381612f4e57612f4d615a0a565b5b0492506020810190505b662386f26fc100008310612f8757662386f26fc100008381612f7d57612f7c615a0a565b5b0492506010810190505b6305f5e1008310612fb0576305f5e1008381612fa657612fa5615a0a565b5b0492506008810190505b6127108310612fd5576127108381612fcb57612fca615a0a565b5b0492506004810190505b60648310612ff85760648381612fee57612fed615a0a565b5b0492506002810190505b600a8310613007576001810190505b80915050919050565b61301c8585858561328e565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146130b5575f6130586128a5565b905060018451036130a4575f6130775f866129b390919063ffffffff16565b90505f61308d5f866129b390919063ffffffff16565b905061309d8389898585896132a0565b50506130b3565b6130b281878787878761344f565b5b505b5050505050565b5f6130e6828473ffffffffffffffffffffffffffffffffffffffff166135fe90919063ffffffff16565b90505f81511415801561310a5750808060200190518101906131089190615ab0565b155b1561314c57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016131439190614d09565b60405180910390fd5b505050565b5f8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b38484604051602401613181929190615cc6565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506131cf8482613613565b6132585761324d848573ffffffffffffffffffffffffffffffffffffffff1663095ea7b3865f604051602401613206929190615d26565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506130bc565b61325784826130bc565b5b50505050565b60608060405191506001825283602083015260408201905060018152826020820152604081016040529250929050565b61329a848484846136d2565b50505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115613447578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401613300959493929190615d9f565b6020604051808303815f875af192505050801561333b57506040513d601f19601f820116820180604052508101906133389190615e0b565b60015b6133bc573d805f8114613369576040519150601f19603f3d011682016040523d82523d5f602084013e61336e565b606091505b505f8151036133b457846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016133ab9190614d09565b60405180910390fd5b805181602001fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461344557846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161343c9190614d09565b60405180910390fd5b505b505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b11156135f6578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b81526004016134af959493929190615e36565b6020604051808303815f875af19250505080156134ea57506040513d601f19601f820116820180604052508101906134e79190615e0b565b60015b61356b573d805f8114613518576040519150601f19603f3d011682016040523d82523d5f602084013e61351d565b606091505b505f81510361356357846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161355a9190614d09565b60405180910390fd5b805181602001fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146135f457846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016135eb9190614d09565b60405180910390fd5b505b505050505050565b606061360b83835f61387b565b905092915050565b5f805f8473ffffffffffffffffffffffffffffffffffffffff168460405161363b9190615ed6565b5f604051808303815f865af19150503d805f8114613674576040519150601f19603f3d011682016040523d82523d5f602084013e613679565b606091505b50915091508180156136a657505f815114806136a55750808060200190518101906136a49190615ab0565b5b5b80156136c857505f8573ffffffffffffffffffffffffffffffffffffffff163b115b9250505092915050565b6136de84848484613944565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036137b7575f805b835181101561379c575f838281518110613731576137306153b4565b5b602002602001015190508060045f878581518110613752576137516153b4565b5b602002602001015181526020019081526020015f205f8282546137759190615792565b9250508190555080836137889190615792565b92505080613795906156d9565b9050613714565b508060055f8282546137ae9190615792565b92505081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613875575f805b8351811015613863575f83828151811061380a576138096153b4565b5b602002602001015190508060045f87858151811061382b5761382a6153b4565b5b602002602001015181526020019081526020015f205f82825403925050819055508083019250508061385c906156d9565b90506137ed565b508060055f8282540392505081905550505b50505050565b6060814710156138c257306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016138b99190614d09565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516138ea9190615ed6565b5f6040518083038185875af1925050503d805f8114613924576040519150601f19603f3d011682016040523d82523d5f602084013e613929565b606091505b5091509150613939868383613cda565b925050509392505050565b805182511461398e57815181516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016139859291906158b8565b60405180910390fd5b5f6139976128a5565b90505f5b8351811015613b99575f6139b882866129b390919063ffffffff16565b90505f6139ce83866129b390919063ffffffff16565b90505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614613af1575f805f8481526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015613a9d57888183856040517f03dee4c5000000000000000000000000000000000000000000000000000000008152600401613a949493929190615eec565b60405180910390fd5b8181035f808581526020019081526020015f205f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614613b8657805f808481526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254613b7e9190615792565b925050819055505b505080613b92906156d9565b905061399b565b506001835103613c54575f613bb75f856129b390919063ffffffff16565b90505f613bcd5f856129b390919063ffffffff16565b90508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051613c459291906158b8565b60405180910390a45050613cd3565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051613cca929190615f2f565b60405180910390a45b5050505050565b606082613cef57613cea82613d67565b613d5f565b5f8251148015613d1557505f8473ffffffffffffffffffffffffffffffffffffffff163b145b15613d5757836040517f9996b315000000000000000000000000000000000000000000000000000000008152600401613d4e9190614d09565b60405180910390fd5b819050613d60565b5b9392505050565b5f81511115613d795780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613de582613dbc565b9050919050565b613df581613ddb565b8114613dff575f80fd5b50565b5f81359050613e1081613dec565b92915050565b5f819050919050565b613e2881613e16565b8114613e32575f80fd5b50565b5f81359050613e4381613e1f565b92915050565b5f8060408385031215613e5f57613e5e613db4565b5b5f613e6c85828601613e02565b9250506020613e7d85828601613e35565b9150509250929050565b613e9081613e16565b82525050565b5f602082019050613ea95f830184613e87565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ee381613eaf565b8114613eed575f80fd5b50565b5f81359050613efe81613eda565b92915050565b5f60208284031215613f1957613f18613db4565b5b5f613f2684828501613ef0565b91505092915050565b5f8115159050919050565b613f4381613f2f565b82525050565b5f602082019050613f5c5f830184613f3a565b92915050565b5f60208284031215613f7757613f76613db4565b5b5f613f8484828501613e35565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015613fc4578082015181840152602081019050613fa9565b5f8484015250505050565b5f601f19601f8301169050919050565b5f613fe982613f8d565b613ff38185613f97565b9350614003818560208601613fa7565b61400c81613fcf565b840191505092915050565b5f6020820190508181035f83015261402f8184613fdf565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61407182613fcf565b810181811067ffffffffffffffff821117156140905761408f61403b565b5b80604052505050565b5f6140a2613dab565b90506140ae8282614068565b919050565b5f67ffffffffffffffff8211156140cd576140cc61403b565b5b602082029050602081019050919050565b5f80fd5b5f6140f46140ef846140b3565b614099565b90508083825260208201905060208402830185811115614117576141166140de565b5b835b81811015614140578061412c8882613e35565b845260208401935050602081019050614119565b5050509392505050565b5f82601f83011261415e5761415d614037565b5b813561416e8482602086016140e2565b91505092915050565b5f67ffffffffffffffff8211156141915761419061403b565b5b602082029050602081019050919050565b5f80fd5b5f67ffffffffffffffff8211156141c0576141bf61403b565b5b6141c982613fcf565b9050602081019050919050565b828183375f83830152505050565b5f6141f66141f1846141a6565b614099565b905082815260208101848484011115614212576142116141a2565b5b61421d8482856141d6565b509392505050565b5f82601f83011261423957614238614037565b5b81356142498482602086016141e4565b91505092915050565b5f61426461425f84614177565b614099565b90508083825260208201905060208402830185811115614287576142866140de565b5b835b818110156142ce57803567ffffffffffffffff8111156142ac576142ab614037565b5b8086016142b98982614225565b85526020850194505050602081019050614289565b5050509392505050565b5f82601f8301126142ec576142eb614037565b5b81356142fc848260208601614252565b91505092915050565b5f67ffffffffffffffff82111561431f5761431e61403b565b5b602082029050602081019050919050565b5f60ff82169050919050565b61434581614330565b811461434f575f80fd5b50565b5f813590506143608161433c565b92915050565b5f61437861437384614305565b614099565b9050808382526020820190506020840283018581111561439b5761439a6140de565b5b835b818110156143c457806143b08882614352565b84526020840193505060208101905061439d565b5050509392505050565b5f82601f8301126143e2576143e1614037565b5b81356143f2848260208601614366565b91505092915050565b5f67ffffffffffffffff8211156144155761441461403b565b5b61441e82613fcf565b9050602081019050919050565b5f61443d614438846143fb565b614099565b905082815260208101848484011115614459576144586141a2565b5b6144648482856141d6565b509392505050565b5f82601f8301126144805761447f614037565b5b813561449084826020860161442b565b91505092915050565b5f805f805f805f80610100898b0312156144b6576144b5613db4565b5b5f6144c38b828c01613e02565b985050602089013567ffffffffffffffff8111156144e4576144e3613db8565b5b6144f08b828c0161414a565b975050604089013567ffffffffffffffff81111561451157614510613db8565b5b61451d8b828c0161414a565b965050606089013567ffffffffffffffff81111561453e5761453d613db8565b5b61454a8b828c016142d8565b955050608089013567ffffffffffffffff81111561456b5761456a613db8565b5b6145778b828c0161414a565b94505060a089013567ffffffffffffffff81111561459857614597613db8565b5b6145a48b828c016143ce565b93505060c089013567ffffffffffffffff8111156145c5576145c4613db8565b5b6145d18b828c016143ce565b92505060e089013567ffffffffffffffff8111156145f2576145f1613db8565b5b6145fe8b828c0161446c565b9150509295985092959890939650565b5f819050919050565b5f61463161462c61462784613dbc565b61460e565b613dbc565b9050919050565b5f61464282614617565b9050919050565b5f61465382614638565b9050919050565b61466381614649565b82525050565b5f60208201905061467c5f83018461465a565b92915050565b5f805f805f8060c0878903121561469c5761469b613db4565b5b5f6146a989828a01613e02565b96505060206146ba89828a01613e02565b95505060406146cb89828a01613e35565b94505060606146dc89828a01613e35565b93505060806146ed89828a01613e35565b92505060a06146fe89828a01613e35565b9150509295509295509295565b5f805f805f60a0868803121561472457614723613db4565b5b5f61473188828901613e02565b955050602061474288828901613e02565b945050604086013567ffffffffffffffff81111561476357614762613db8565b5b61476f8882890161414a565b935050606086013567ffffffffffffffff8111156147905761478f613db8565b5b61479c8882890161414a565b925050608086013567ffffffffffffffff8111156147bd576147bc613db8565b5b6147c98882890161446c565b9150509295509295909350565b5f6147e082614638565b9050919050565b6147f0816147d6565b82525050565b5f6020820190506148095f8301846147e7565b92915050565b5f6020828403121561482457614823613db4565b5b5f61483184828501614352565b91505092915050565b5f80604083850312156148505761484f613db4565b5b5f83013567ffffffffffffffff81111561486d5761486c613db8565b5b6148798582860161414a565b925050602083013567ffffffffffffffff81111561489a57614899613db8565b5b6148a6858286016142d8565b9150509250929050565b5f67ffffffffffffffff8211156148ca576148c961403b565b5b602082029050602081019050919050565b5f6148ed6148e8846148b0565b614099565b905080838252602082019050602084028301858111156149105761490f6140de565b5b835b8181101561493957806149258882613e02565b845260208401935050602081019050614912565b5050509392505050565b5f82601f83011261495757614956614037565b5b81356149678482602086016148db565b91505092915050565b5f806040838503121561498657614985613db4565b5b5f83013567ffffffffffffffff8111156149a3576149a2613db8565b5b6149af85828601614943565b925050602083013567ffffffffffffffff8111156149d0576149cf613db8565b5b6149dc8582860161414a565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b614a1881613e16565b82525050565b5f614a298383614a0f565b60208301905092915050565b5f602082019050919050565b5f614a4b826149e6565b614a5581856149f0565b9350614a6083614a00565b805f5b83811015614a90578151614a778882614a1e565b9750614a8283614a35565b925050600181019050614a63565b5085935050505092915050565b5f6020820190508181035f830152614ab58184614a41565b905092915050565b5f60208284031215614ad257614ad1613db4565b5b5f82013567ffffffffffffffff811115614aef57614aee613db8565b5b614afb84828501614225565b91505092915050565b5f614b0e82614638565b9050919050565b614b1e81614b04565b82525050565b5f602082019050614b375f830184614b15565b92915050565b5f805f60608486031215614b5457614b53613db4565b5b5f614b6186828701613e02565b935050602084013567ffffffffffffffff811115614b8257614b81613db8565b5b614b8e8682870161414a565b925050604084013567ffffffffffffffff811115614baf57614bae613db8565b5b614bbb8682870161414a565b9150509250925092565b5f805f805f60a08688031215614bde57614bdd613db4565b5b5f614beb88828901613e02565b9550506020614bfc88828901613e02565b9450506040614c0d88828901613e35565b9350506060614c1e88828901613e35565b9250506080614c2f88828901613e35565b9150509295509295909350565b5f805f8060808587031215614c5457614c53613db4565b5b5f614c6187828801613e02565b9450506020614c7287828801613e35565b9350506040614c8387828801613e35565b925050606085013567ffffffffffffffff811115614ca457614ca3613db8565b5b614cb08782880161446c565b91505092959194509250565b5f8060408385031215614cd257614cd1613db4565b5b5f614cdf85828601613e35565b9250506020614cf085828601613e35565b9150509250929050565b614d0381613ddb565b82525050565b5f602082019050614d1c5f830184614cfa565b92915050565b614d2b81613f2f565b8114614d35575f80fd5b50565b5f81359050614d4681614d22565b92915050565b5f8060408385031215614d6257614d61613db4565b5b5f614d6f85828601613e02565b9250506020614d8085828601614d38565b9150509250929050565b5f614d9482613ddb565b9050919050565b614da481614d8a565b8114614dae575f80fd5b50565b5f81359050614dbf81614d9b565b92915050565b5f8060408385031215614ddb57614dda613db4565b5b5f614de885828601614db1565b9250506020614df985828601613e35565b9150509250929050565b5f80fd5b5f8083601f840112614e1c57614e1b614037565b5b8235905067ffffffffffffffff811115614e3957614e38614e03565b5b602083019150836020820283011115614e5557614e546140de565b5b9250929050565b5f8083601f840112614e7157614e70614037565b5b8235905067ffffffffffffffff811115614e8e57614e8d614e03565b5b602083019150836001820283011115614eaa57614ea96140de565b5b9250929050565b5f805f805f805f8060a0898b031215614ecd57614ecc613db4565b5b5f614eda8b828c01613e02565b9850506020614eeb8b828c01613e02565b975050604089013567ffffffffffffffff811115614f0c57614f0b613db8565b5b614f188b828c01614e07565b9650965050606089013567ffffffffffffffff811115614f3b57614f3a613db8565b5b614f478b828c01614e07565b9450945050608089013567ffffffffffffffff811115614f6a57614f69613db8565b5b614f768b828c01614e5c565b92509250509295985092959890939650565b614f9181613eaf565b82525050565b5f602082019050614faa5f830184614f88565b92915050565b5f805f60608486031215614fc757614fc6613db4565b5b5f614fd486828701613e35565b9350506020614fe586828701613e35565b9250506040614ff686828701614352565b9150509250925092565b61500981614330565b82525050565b5f6080820190506150225f830187613e87565b61502f6020830186615000565b61503c6040830185615000565b818103606083015261504e8184613fdf565b905095945050505050565b5f806040838503121561506f5761506e613db4565b5b5f61507c85828601613e02565b925050602061508d85828601613e02565b9150509250929050565b5f805f805f8060a087890312156150b1576150b0613db4565b5b5f6150be89828a01613e02565b96505060206150cf89828a01613e02565b95505060406150e089828a01613e35565b94505060606150f189828a01613e35565b935050608087013567ffffffffffffffff81111561511257615111613db8565b5b61511e89828a01614e5c565b92509250509295509295509295565b5f805f805f60a0868803121561514657615145613db4565b5b5f61515388828901613e02565b955050602061516488828901613e02565b945050604061517588828901613e35565b935050606061518688828901613e35565b925050608086013567ffffffffffffffff8111156151a7576151a6613db8565b5b6151b38882890161446c565b9150509295509295909350565b5f602082840312156151d5576151d4613db4565b5b5f6151e284828501613e02565b91505092915050565b5f805f6060848603121561520257615201613db4565b5b5f61520f86828701613e02565b935050602061522086828701613e35565b925050604061523186828701613e35565b9150509250925092565b5f806040838503121561525157615250613db4565b5b5f61525e85828601613e35565b925050602061526f85828601614352565b9150509250929050565b5f60208201905061528c5f830184615000565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806152d657607f821691505b6020821081036152e9576152e8615292565b5b50919050565b5f81905092915050565b5f61530382613f8d565b61530d81856152ef565b935061531d818560208601613fa7565b80840191505092915050565b5f61533482856152f9565b915061534082846152f9565b91508190509392505050565b7f496e76616c6964207265717565737400000000000000000000000000000000005f82015250565b5f615380600f83613f97565b915061538b8261534c565b602082019050919050565b5f6020820190508181035f8301526153ad81615374565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f546f6b656e20494420616c7265616479206578697374730000000000000000005f82015250565b5f615415601783613f97565b9150615420826153e1565b602082019050919050565b5f6020820190508181035f83015261544281615409565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026154a57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8261546a565b6154af868361546a565b95508019841693508086168417925050509392505050565b5f6154e16154dc6154d784613e16565b61460e565b613e16565b9050919050565b5f819050919050565b6154fa836154c7565b61550e615506826154e8565b848454615476565b825550505050565b5f90565b615522615516565b61552d8184846154f1565b505050565b5b81811015615550576155455f8261551a565b600181019050615533565b5050565b601f8211156155955761556681615449565b61556f8461545b565b8101602085101561557e578190505b61559261558a8561545b565b830182615532565b50505b505050565b5f82821c905092915050565b5f6155b55f198460080261559a565b1980831691505092915050565b5f6155cd83836155a6565b9150826002028217905092915050565b6155e682613f8d565b67ffffffffffffffff8111156155ff576155fe61403b565b5b61560982546152bf565b615614828285615554565b5f60209050601f831160018114615645575f8415615633578287015190505b61563d85826155c2565b8655506156a4565b601f19841661565386615449565b5f5b8281101561567a57848901518255600182019150602085019450602081019050615655565b868310156156975784890151615693601f8916826155a6565b8355505b6001600288020188555050505b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6156e382613e16565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615715576157146156ac565b5b600182019050919050565b5f61572a82613e16565b915061573583613e16565b925082820390508181111561574d5761574c6156ac565b5b92915050565b5f8151905061576181613e1f565b92915050565b5f6020828403121561577c5761577b613db4565b5b5f61578984828501615753565b91505092915050565b5f61579c82613e16565b91506157a783613e16565b92508282019050808211156157bf576157be6156ac565b5b92915050565b5f610100820190506157d95f83018b614cfa565b6157e6602083018a614cfa565b6157f36040830189613e87565b6158006060830188613e87565b61580d6080830187613e87565b61581a60a0830186613e87565b61582760c0830185614cfa565b61583460e0830184613e87565b9998505050505050505050565b5f805f6060848603121561585857615857613db4565b5b5f61586586828701615753565b935050602061587686828701615753565b925050604061588786828701615753565b9150509250925092565b5f6040820190506158a45f830185614cfa565b6158b16020830184614cfa565b9392505050565b5f6040820190506158cb5f830185613e87565b6158d86020830184613e87565b9392505050565b5f815190506158ed81613dec565b92915050565b5f6020828403121561590857615907613db4565b5b5f615915848285016158df565b91505092915050565b5f60e0820190506159315f83018a614cfa565b61593e6020830189614cfa565b61594b6040830188613e87565b6159586060830187613e87565b6159656080830186613e87565b61597260a0830185614cfa565b61597f60c0830184613e87565b98975050505050505050565b5f80604083850312156159a1576159a0613db4565b5b5f6159ae85828601615753565b92505060206159bf85828601615753565b9150509250929050565b5f6159d382613e16565b91506159de83613e16565b92508282026159ec81613e16565b91508282048414831517615a0357615a026156ac565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f615a4182613e16565b9150615a4c83613e16565b925082615a5c57615a5b615a0a565b5b828204905092915050565b5f606082019050615a7a5f830186614cfa565b615a876020830185614cfa565b615a946040830184613e87565b949350505050565b5f81519050615aaa81614d22565b92915050565b5f60208284031215615ac557615ac4613db4565b5b5f615ad284828501615a9c565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b615b0d81613ddb565b82525050565b5f615b1e8383615b04565b60208301905092915050565b5f602082019050919050565b5f615b4082615adb565b615b4a8185615ae5565b9350615b5583615af5565b805f5b83811015615b85578151615b6c8882615b13565b9750615b7783615b2a565b925050600181019050615b58565b5085935050505092915050565b5f60a082019050615ba55f830188613e87565b615bb26020830187613e87565b8181036040830152615bc48186615b36565b9050615bd36060830185614cfa565b615be06080830184613e87565b9695505050505050565b5f615bfc615bf7846140b3565b614099565b90508083825260208201905060208402830185811115615c1f57615c1e6140de565b5b835b81811015615c485780615c348882615753565b845260208401935050602081019050615c21565b5050509392505050565b5f82601f830112615c6657615c65614037565b5b8151615c76848260208601615bea565b91505092915050565b5f60208284031215615c9457615c93613db4565b5b5f82015167ffffffffffffffff811115615cb157615cb0613db8565b5b615cbd84828501615c52565b91505092915050565b5f604082019050615cd95f830185614cfa565b615ce66020830184613e87565b9392505050565b5f819050919050565b5f615d10615d0b615d0684615ced565b61460e565b613e16565b9050919050565b615d2081615cf6565b82525050565b5f604082019050615d395f830185614cfa565b615d466020830184615d17565b9392505050565b5f81519050919050565b5f82825260208201905092915050565b5f615d7182615d4d565b615d7b8185615d57565b9350615d8b818560208601613fa7565b615d9481613fcf565b840191505092915050565b5f60a082019050615db25f830188614cfa565b615dbf6020830187614cfa565b615dcc6040830186613e87565b615dd96060830185613e87565b8181036080830152615deb8184615d67565b90509695505050505050565b5f81519050615e0581613eda565b92915050565b5f60208284031215615e2057615e1f613db4565b5b5f615e2d84828501615df7565b91505092915050565b5f60a082019050615e495f830188614cfa565b615e566020830187614cfa565b8181036040830152615e688186614a41565b90508181036060830152615e7c8185614a41565b90508181036080830152615e908184615d67565b90509695505050505050565b5f81905092915050565b5f615eb082615d4d565b615eba8185615e9c565b9350615eca818560208601613fa7565b80840191505092915050565b5f615ee18284615ea6565b915081905092915050565b5f608082019050615eff5f830187614cfa565b615f0c6020830186613e87565b615f196040830185613e87565b615f266060830184613e87565b95945050505050565b5f6040820190508181035f830152615f478185614a41565b90508181036020830152615f5b8184614a41565b9050939250505056fea264697066735822122051efa173c94ef6b52f8eb5e62dcf4be19b02bd8a285c990213930cb047bdb76964736f6c63430008140033

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

0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000088ee7a3537667958d040216d9dc1752d1274d838

-----Decoded View---------------
Arg [0] : _router (address): 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Arg [1] : _factory (address): 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
Arg [2] : _usdtToken (address): 0xdAC17F958D2ee523a2206206994597C13D831ec7
Arg [3] : _mmcToken (address): 0x88eE7a3537667958D040216D9Dc1752D1274D838

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d
Arg [1] : 0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f
Arg [2] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [3] : 00000000000000000000000088ee7a3537667958d040216d9dc1752d1274d838


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.