ETH Price: $2,043.45 (-4.89%)

Token

OSM Subscription (OSM)
 

Overview

Max Total Supply

16 OSM

Holders

16

Transfers

-
0 (0%)

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

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

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
OSMSubscription

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./TokenReceiver.sol";
import "./Mintable.sol";
import "./Nameable.sol";
import { DiscountIsInvalid } from "./SetSubscribable.sol";

error ZeroAddress(address zero);
contract OSMSubscription is TokenReceiver {  
    event CommissionPaid(address wallet, uint256 amount); 
    constructor(string memory name, string memory symbol) Subscribable(name,symbol) {}          

    function payOutFees(uint256 numberOfDays, string memory discountCode) internal {
        uint256 fee = determineFee(numberOfDays,discountCode);
        address payable partner = payable(subs.promoDiscounts[discountCode].partner);
        uint256 commission = determineCommission(fee, discountCode);
            
        if (commission > 0) {
            partner.transfer(commission);
            emit CommissionPaid(subs.promoDiscounts[discountCode].partner, commission);
        }        
        OSM_TREASURY_WALLET.transfer(fee-commission);
        subs.promoDiscounts[discountCode].timesUsed = subs.promoDiscounts[discountCode].timesUsed + 1; 
    }       

    function mint(uint256 numberOfDays) external payable {
        payOutFees(numberOfDays, blank);
        _mintTokenFor(msg.sender,numberOfDays);     
    }  

    function discountMint(uint256 numberOfDays, string calldata discountCode) external payable {          
        if (!subs.promoDiscounts[discountCode].exists || subs.promoDiscounts[discountCode].expires < block.timestamp) {
            revert DiscountIsInvalid(discountCode);
        }        
        payOutFees(numberOfDays, discountCode);
        subs.promoDiscounts[discountCode].timesUsed = subs.promoDiscounts[discountCode].timesUsed + 1;
        _mintTokenFor(msg.sender,numberOfDays,discountCode);          
    }    

    function mintForRecipient(address recipient, uint256 numberOfDays) external onlyOwner { 
        establishSubscription(incrementMint(recipient),numberOfDays);  
    }

    function _mintTokenFor(address recipient, uint256 numberOfDays) internal {
        _mintTokenFor(recipient,numberOfDays,blank);
    }
    function _mintTokenFor(address recipient, uint256 numberOfDays, string memory discountCode) internal {
        commitSubscription(incrementMint(recipient), numberOfDays, discountCode);  
    }

    function incrementMint(address recipient) private returns (uint256) {
        uint256 tokenId = totalSupply()+1;
        _mint(recipient,tokenId);
        return tokenId;
    }

    function renewOSM(uint256 tokenId, uint256 numberOfDays) public payable {
        renewOSM(tokenId, numberOfDays, blank);
    }

    function renewOSM(uint256 tokenId, uint256 numberOfDays, string memory discountCode) public payable {
        payOutFees(numberOfDays, discountCode);
        renewSubscription(tokenId, numberOfDays, discountCode);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

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

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

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

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

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

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

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

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

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

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

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

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

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

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

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

File 4 of 26 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @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, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * 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.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @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`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./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);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "./Ownable.sol";
import "./Nameable.sol";
import { TokenNonOwner } from "./SetOwnerEnumerable.sol";
import { OwnerEnumerable } from "./OwnerEnumerable.sol";
import { SetApprovable, ApprovableData, TokenNonExistent } from "./SetApprovable.sol";

abstract contract Approvable is OwnerEnumerable {  
    using SetApprovable for ApprovableData; 
    ApprovableData approvable;
 
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return approvable.isApprovedForAll(owner,operator);
    }  

    function approve(address to, uint256 tokenId) public virtual override {  
        if (ownerOf(tokenId) != msg.sender) {
            revert TokenNonOwner(msg.sender,tokenId);
        }        
        approvable.approveForToken(to, tokenId);
        emit Approval(ownerOf(tokenId), to, tokenId);        
    }  

    function setApprovalForAll(address operator, bool approved) public virtual override {   
        if (approved) {
            approvable.approveForContract(operator);
        } else {
            approvable.revokeApprovalForContract(operator, msg.sender);
        }        
    }       

    function validateApprovedOrOwner(address spender, uint256 tokenId) internal view {
        address owner = ownerOf(tokenId);
        if (!(spender == owner || isApprovedForAll(owner, spender) || approvable.getApproved(tokenId) == spender)) {
            revert TokenNonOwner(spender, tokenId);
        }
    }  

    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        requireMinted(tokenId);
        return approvable.tokens[tokenId].approval;
    }       

    function revokeTokenApproval(uint256 tokenId) internal {
        approvable.revokeTokenApproval(tokenId);
    }

    function revokeApprovals(address holder) internal {
        approvable.revokeApprovals(holder,tokensOwnedBy(holder));                    
    }


    /**
     * @dev Reverts if the `tokenId` has not been minted yet.
     */
    function requireMinted(uint256 tokenId) internal view virtual {
        if (!exists(tokenId)) {
            revert TokenNonExistent(tokenId);
        }
    }    

    function exists(uint256 tokenId) internal view virtual returns (bool) {
        return approvable.tokens[tokenId].exists;
    }      
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { SetContractable, ContractableData, AllowedContract, AllowedPath } from "./SetContractable.sol";
import "./Mintable.sol";


abstract contract Contractable is Mintable {  
    using SetContractable for ContractableData;
    ContractableData contractables;
    function balanceOfAllowance(address wallet) public view returns (uint256) {
        return contractables.balanceOfAllowance(wallet);
    }
    function allowances(address wallet) public view returns (AllowedContract [] memory) {
        return contractables.allowances(wallet);
    }
    function allowContract(address allowed, string calldata urlPath, string calldata erc, uint256 balanceRequired, bool isStaking, bool isProxy) public {
        contractables.allowContract(allowed, urlPath, erc, balanceRequired, isStaking, isProxy);
    }
    function pathAllows(string calldata path) public view returns (AllowedPath memory) {
        return contractables.pathAllows(path);
    }
    function revokeContract(address revoked) public {
        contractables.revokeContract(revoked);
    }    
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "./Ownable.sol";
import { SetFlexibleMetadataData, FlexibleMetadataData } from "./SetFlexibleMetadata.sol";
uint256 constant DEFAULT = 1;
uint256 constant FLAG = 2;
uint256 constant PRE = 3;
abstract contract FlexibleMetadata is Ownable, Context, ERC165, IERC721, IERC721Metadata {  
    using SetFlexibleMetadataData for FlexibleMetadataData;
    FlexibleMetadataData flexible;   

    string tokenName;
    string tokenSymbol;
    constructor(string memory _name, string memory _symbol) {
        tokenName = _name;
        tokenSymbol = _symbol;
    }

    function name() public virtual override view returns (string memory) {
        return tokenName;
    }  

    function symbol() public virtual override view returns (string memory) {
        return tokenSymbol;
    }      
    
    function setContractUri(string memory uri) public onlyOwner {
        flexible.setContractMetadataURI(uri);
    }

    function reveal(bool _reveal) public onlyOwner {
        flexible.reveal(_reveal);
    }

    function setTokenUri(string memory uri, uint256 tokenType) public {
        if (tokenType == FLAG) {
            flexible.setFlaggedTokenMetadataURI(uri);
        }
        else if (tokenType == PRE) {
            flexible.setPrerevealTokenMetadataURI(uri);
        } else {
            flexible.setDefaultTokenMetadataURI(uri);
        }
    }

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

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {        
        return flexible.getTokenMetadata(tokenId);
    }          
    function contractURI() public view returns (string memory) {
        return flexible.getContractMetadata();
    }    
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./Approvable.sol";
import { SetLockable, LockableStatus,  LockableData, WalletLockedByOwner } from "./SetLockable.sol";
abstract contract Lockable is Approvable {    
    using SetLockable for LockableData; 
    LockableData lockable;

    function custodianOf(uint256 id)
        public
        view
        returns (address)
    {             
        return lockable.findCustodian(ownerOf(id));
    }     

    function lockWallet(uint256 id) public {   
        address owner = ownerOf(id);
        revokeApprovals(owner);
        lockable.lockWallet(owner);
    }

    function unlockWallet(uint256 id) public {              
        lockable.unlockWallet(ownerOf(id));
    }    

    function _forceUnlock(uint256 id) internal {  
        lockable.forceUnlock(ownerOf(id));
    }    

    function setCustodian(uint256 id, address custodianAddress) public {       
        lockable.setCustodian(custodianAddress,ownerOf(id));
    }

    function isLocked(uint256 id) public view returns (bool) {     
        return lockable.lockableStatus[ownerOf(id)].isLocked;
    } 

    function lockedSince(uint256 id) public view returns (uint256) {     
        return lockable.lockableStatus[ownerOf(id)].lockedAt;
    }     

    function validateLock(uint256 tokenId) internal view {
        if (isLocked(tokenId)) {
            revert WalletLockedByOwner();
        }
    }

    function initializeLockable(address wallet, LockableStatus memory status) internal {
       lockable.lockableStatus[wallet] = status;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "./Lockable.sol";
import { LockableStatus } from "./SetLockable.sol";

error InvalidTransferRecipient();
error NotApprovedOrOwner();
error InvalidOwner();
error OnlyOneSubscriptionPerWallet(uint256 balance);
error ContractIsNot721Receiver();

abstract contract LockableTransferrable is Lockable {  
    using Address for address;

    function approve(address to, uint256 tokenId) public virtual override {  
        validateLock(tokenId);
        super.approve(to,tokenId);      
    }  

    function setApprovalForAll(address operator, bool approved) public virtual override {   
        validateLock(tokensOwnedBy(msg.sender)[0]);
        super.setApprovalForAll(operator,approved);     
    }        

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {        
        validateApprovedOrOwner(msg.sender, tokenId);
        validateLock(tokenId);
        _transfer(from,to,tokenId);
    }

    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal {
                
        if (balanceOf(to) > 0) {
            revert OnlyOneSubscriptionPerWallet(balanceOf(to));
        } 
        if(to == address(0)) {
            revert InvalidTransferRecipient();
        }

        revokeTokenApproval(tokenId);   

        swapOwner(from,to,tokenId);     

        completeTransfer(from,to,tokenId);    
    }   

    function completeTransfer(
        address from,
        address to,
        uint256 tokenId) internal {

        emit Transfer(from, to, tokenId);

        address[] memory approvedAll;
    
        initializeLockable(to,LockableStatus(false,0,address(0),0,approvedAll,true)); 
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }    

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public virtual override {
        validateApprovedOrOwner(msg.sender, tokenId);
        validateLock(tokenId);
        _safeTransfer(from, to, tokenId, data);
    }     

    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        if (!_checkOnERC721Received(from, to, tokenId, data)) {
            revert ContractIsNot721Receiver();
        }        
        _transfer(from, to, tokenId);
    }

    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data) returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert InvalidTransferRecipient();
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }    

}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./LockableTransferrable.sol";

error InvalidRecipient(address zero);
error TokenAlreadyMinted(uint256 tokenId);
error MintIsNotLive();

abstract contract Mintable is LockableTransferrable {  
    bool isLive;
    uint256 tokenCount;

    function setMintLive(bool _isLive) public onlyOwner {
        isLive = _isLive;
    } 

    function _mint(address to, uint256 tokenId) internal virtual {
        if (!isLive) {
            revert MintIsNotLive();
        }
        if (to == address(0)) {
            revert InvalidRecipient(to);
        }
        if (exists(tokenId)) {
            revert TokenAlreadyMinted(tokenId);
        }

        tokenCount +=1;

        enumerateMint(to, tokenId);

        completeTransfer(address(0),to,tokenId);
    }         

    function totalSupply() public view returns (uint256) {
        return tokenCount;
    }
}

File 15 of 26 : Nameable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";


abstract contract Nameable is IERC721Metadata {      
    string tokenName;
    string tokenSymbol;
    constructor(string memory _name, string memory _symbol) {
        tokenName = _name;
        tokenSymbol = _symbol;
    }

    function name() public virtual override view returns (string memory) {
        return tokenName;
    }  

    function symbol() public virtual override view returns (string memory) {
        return tokenSymbol;
    }          
      
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @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.
 *
 * By default, the owner account will be the one that deploys the contract. 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 {
    address private _owner;

    error CallerIsNotOwner(address caller);
    error OwnerCannotBeZeroAddress();

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(msg.sender);
    }

    /**
     * @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() != msg.sender) {
            revert CallerIsNotOwner(msg.sender);
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing 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 OwnerCannotBeZeroAddress();
        }
        _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);
    }
    
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { SetOwnerEnumerable, OwnerEnumerableData, TokenNonOwner, InvalidOwner } from "./SetOwnerEnumerable.sol";
import { FlexibleMetadata } from "./FlexibleMetadata.sol";


abstract contract OwnerEnumerable is FlexibleMetadata {  
    using SetOwnerEnumerable for OwnerEnumerableData;
    OwnerEnumerableData enumerable;
    
    function ownerOf(uint256 tokenId) public view returns (address) {
        return enumerable.ownerOf(tokenId);
    }

    function tokensOwnedBy(address holder) public view returns (uint256[] memory) {
        return enumerable.findTokensOwned(holder);
    }

    function balanceOf(address owner) public view virtual override returns (uint256) {
        validateNonZeroAddress(owner);
        return enumerable.ownedTokens[owner].length;
    }   
    function validateNonZeroAddress(address owner) internal pure {
        if(owner == address(0)) {
            revert InvalidOwner();
        }
    }
    
    function enumerateMint(address to, uint256 tokenId) internal {
        enumerable.addTokenToEnumeration(to, tokenId);
    }

    function swapOwner(address from, address to, uint256 tokenId) internal {
        enumerable.removeTokenFromEnumeration(from, tokenId);
        enumerable.removeTokenFromEnumeration(from, tokenId);
        enumerable.addTokenToEnumeration(to, tokenId);
    }
    
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

struct ApprovableData { 

    mapping(address => uint256) contractApprovals;
    mapping(address => address[]) approvedForAll;
    mapping(address => mapping(address => uint256)) approvedForAllIndex;

    mapping(uint256 => uint256) tokenApprovals;
    mapping(uint256 => TokenApproval[]) approvedForToken;
    mapping(uint256 => mapping(address => uint256)) approvedForTokenIndex;

    mapping(uint256 => TokenApproval) tokens;

    bool exists;
}    

struct TokenApproval {
    address approval;
    bool exists;
}

error AlreadyApproved(address operator, uint256 tokenId);
error AlreadyApprovedContract(address operator);
error AlreadyRevoked(address operator, uint256 tokenId);
error AlreadyRevokedContract(address operator);
error TokenNonExistent(uint256 tokenId);


library SetApprovable {     

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

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

    function isApprovedForAll(ApprovableData storage self, address owner, address operator) public view returns (bool) {        
        return self.approvedForAll[owner].length > self.approvedForAllIndex[owner][operator] ? 
            (self.approvedForAll[owner][self.approvedForAllIndex[owner][operator]] != address(0)) :
            false;
    }   

    function revokeApprovals(ApprovableData storage self, address owner, uint256[] memory ownedTokens) public {            
        
        for (uint256 i = 0; i < ownedTokens.length; i++) {
            revokeTokenApproval(self,ownedTokens[i]);
        }
        
        address[] memory contractApprovals = self.approvedForAll[owner];
        for (uint256 i = 0; i < contractApprovals.length; i++) {
            address approved = contractApprovals[i];    
            revokeApprovalForContract(self, approved, owner);             
        }
    }   

    function revokeTokenApproval(ApprovableData storage self, uint256 token) public {            
        TokenApproval[] memory approvals = self.approvedForToken[token];
        for (uint256 j = 0; j < approvals.length; j++) {
            revokeApprovalForToken(self, approvals[j].approval, token);
        }         
    }       

    function getApproved(ApprovableData storage self, uint256 tokenId) public view returns (address) {
        return self.approvedForToken[tokenId].length > 0 ? self.approvedForToken[tokenId][0].approval : address(0);
    }     

    function approveForToken(ApprovableData storage self, address operator, uint256 tokenId) public {
        uint256 index = self.approvedForTokenIndex[tokenId][operator];
        if (index < self.approvedForToken[tokenId].length && self.approvedForToken[tokenId][index].exists) {
            revert AlreadyApproved(operator, tokenId);
        }
   
        self.approvedForToken[tokenId].push(TokenApproval(operator,true));
        self.approvedForTokenIndex[tokenId][operator] = self.approvedForToken[tokenId].length-1;
        self.tokenApprovals[tokenId]++;
        
        emit Approval(msg.sender, operator, tokenId); 
    } 

    function revokeApprovalForToken(ApprovableData storage self, address revoked, uint256 tokenId) public {
        uint256 index = self.approvedForTokenIndex[tokenId][revoked];
        if (!self.approvedForToken[tokenId][index].exists) {
            revert AlreadyRevoked(revoked,tokenId);
        }
        
        // When the token to delete is not the last token, the swap operation is unnecessary
        if (index != self.approvedForToken[tokenId].length - 1) {
            TokenApproval storage tmp = self.approvedForToken[tokenId][self.approvedForToken[tokenId].length - 1];
            self.approvedForToken[tokenId][self.approvedForToken[tokenId].length - 1] = self.approvedForToken[tokenId][index];
            self.approvedForToken[tokenId][index] = tmp;
            self.approvedForTokenIndex[tokenId][tmp.approval] = index;            
        }

        // This also deletes the contents at the last position of the array
        delete self.approvedForTokenIndex[tokenId][revoked];
        self.approvedForToken[tokenId].pop();

        self.tokenApprovals[tokenId]--;
    }

    function approveForContract(ApprovableData storage self, address operator) public {
        uint256 index = self.approvedForAllIndex[msg.sender][operator];
        if (self.approvedForAll[msg.sender].length > index &&
            self.approvedForAll[msg.sender][index] != address(0)) {
            revert AlreadyApprovedContract(self.approvedForAll[msg.sender][index]);
        }
   
        self.approvedForAll[msg.sender].push(operator);
        self.approvedForAllIndex[msg.sender][operator] = self.approvedForAll[msg.sender].length-1;
        self.contractApprovals[msg.sender]++;

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

    function revokeApprovalForContract(ApprovableData storage self, address revoked, address owner) public {
        uint256 index = self.approvedForAllIndex[owner][revoked];
        address revokee = self.approvedForAll[owner][index];
        if (revokee != revoked) {
            revert AlreadyRevokedContract(revoked);
        }
        
        // When the token to delete is not the last token, the swap operation is unnecessary
        if (index != self.approvedForAll[owner].length - 1) {
            address tmp = self.approvedForAll[owner][self.approvedForAll[owner].length - 1];
            self.approvedForAll[owner][self.approvedForAll[owner].length - 1] = self.approvedForAll[owner][index];
            self.approvedForAll[owner][index] = tmp;
            self.approvedForAllIndex[owner][tmp] = index;            
        }
        // This also deletes the contents at the last position of the array
        delete self.approvedForAllIndex[owner][revoked];
        self.approvedForAll[owner].pop();

        self.contractApprovals[owner]--;

        emit ApprovalForAll(owner, revoked, false); 
    }    

}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

struct AllowedContract {
    address addressed;
    string urlPath;
    string erc;
    uint256 balanceRequired;
    bool isStaking;
    bool isProxy;
    bool exists;
}

struct AllowedPath {
    address[] addresses;
    address wallet;
    bool exists;
}

struct ContractableData { 
    mapping(address => AllowedContract[]) contractAllowlist;
    mapping(string => AllowedPath) paths;
    mapping(address => mapping(address => uint256)) contractIndexList;
    
    mapping(address => uint256) allowanceBalances;
}    

library SetContractable {

    error AlreadyAllowed(address requester, address contracted);  
    error PathAlreadyInUse(string path);   
    error PathDoesNotExist(string path);  
    error WTF(bool success,address wtf);
    error IsNotAllowed(address requester, address contracted); 
    
    function balanceOfAllowance(ContractableData storage self, address wallet) public view returns (uint256) {        
        return self.allowanceBalances[wallet];
    }     

    function allowances(ContractableData storage self, address wallet) public view returns (AllowedContract [] memory) {
        return self.contractAllowlist[wallet];
    }

    function addAllowance(ContractableData storage self, address allowed, string calldata urlPath, string calldata erc, uint256 balanceRequired, bool isStaking, bool isProxy) public {
        self.contractIndexList[msg.sender][allowed] = balanceOfAllowance(self,msg.sender);
        self.contractAllowlist[msg.sender].push(AllowedContract(allowed,urlPath,erc,balanceRequired,isStaking,isProxy,true));        
        self.allowanceBalances[msg.sender]++;
    }

    function allowContract(
        ContractableData storage self, 
        address allowed, 
        string calldata urlPath, 
        string calldata erc,
        uint256 balanceRequired,
        bool isStaking, 
        bool isProxy) public {
        if (self.paths[urlPath].exists && self.paths[urlPath].wallet != msg.sender) {
            revert PathAlreadyInUse(urlPath);
        } else if (balanceOfAllowance(self, msg.sender) > 0 && !self.paths[urlPath].exists) {
            for (uint256 i = 0; i < balanceOfAllowance(self, msg.sender); i++) {
                AllowedContract storage existing = self.contractAllowlist[msg.sender][i];
                if (self.paths[existing.urlPath].exists) {
                    delete self.paths[existing.urlPath];
                }
                existing.urlPath = urlPath;
            }
        } 
        if (balanceOfAllowance(self,msg.sender) != 0) {
            uint256 index = self.contractIndexList[msg.sender][allowed];
            if (self.contractAllowlist[msg.sender][index].addressed == allowed) {
                revert AlreadyAllowed(msg.sender,allowed);
            }
        }
        addAllowance(self,allowed,urlPath,erc,balanceRequired,isStaking,isProxy);

        address[] memory addressed = new address[](balanceOfAllowance(self, msg.sender));
        for (uint256 i = 0; i < balanceOfAllowance(self, msg.sender); i++) {
            addressed[i] = self.contractAllowlist[msg.sender][i].addressed;
        }
        self.paths[urlPath] = AllowedPath(addressed,msg.sender,balanceOfAllowance(self, msg.sender) > 0);
    } 

    function removeAllowance(ContractableData storage self, address allowed, string calldata urlPath, string calldata erc, uint256 balanceRequired, bool isStaking, bool isProxy) public {
        self.contractIndexList[msg.sender][allowed] = balanceOfAllowance(self,msg.sender);
        self.contractAllowlist[msg.sender].push(AllowedContract(allowed,urlPath,erc,balanceRequired,isStaking,isProxy,true));        
        self.allowanceBalances[msg.sender]++;
    }    

    function revokeContract(ContractableData storage self, address revoked) public {
        uint256 length = self.contractAllowlist[msg.sender].length;
        uint256 revokedIndex = self.contractIndexList[msg.sender][revoked];
        AllowedContract storage revokee = self.contractAllowlist[msg.sender][revokedIndex];
        // When the token to delete is the last token, the swap operation is unnecessary
        if (revokedIndex < length - 1) {
            AllowedContract memory lastItem = self.contractAllowlist[msg.sender][length - 1];
            self.contractAllowlist[msg.sender][revokedIndex] = lastItem; // Move the last token to the slot of the to-delete token
            self.contractIndexList[msg.sender][lastItem.addressed] = revokedIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete self.contractIndexList[msg.sender][revoked];
        self.contractAllowlist[msg.sender].pop();
        self.allowanceBalances[msg.sender]--;

        uint256 balanced = balanceOfAllowance(self, msg.sender);
        if (balanced > 0) {            
            address[] memory addressed = new address[](balanceOfAllowance(self, msg.sender));
            for (uint256 i = 0; i < balanceOfAllowance(self, msg.sender); i++) {
                addressed[i] = self.contractAllowlist[msg.sender][i].addressed;
            }
            self.paths[revokee.urlPath] = AllowedPath(addressed,msg.sender,true);
        } else {
            address[] memory addressed = new address[](0);
            self.paths[revokee.urlPath] = AllowedPath(addressed,msg.sender,false);      
        }

        
    }

    function pathAllows(ContractableData storage self, string calldata path) public view returns (AllowedPath memory) {
        if (!self.paths[path].exists) {
            revert PathDoesNotExist(path);
        }
        return self.paths[path];
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

struct FlexibleMetadataData { 
    string defaultTokenMetadata;
    string prerevealTokenMetadata;
    string flaggedTokenMetadata;
    string contractMetadata;
    mapping(uint256 => bool) tokenFlag;
    bool tokenReveal; 
}    
bytes16 constant _SYMBOLS = "0123456789abcdef";
library SetFlexibleMetadataData {
    function setDefaultTokenMetadataURI(FlexibleMetadataData storage self, string memory uri) public {
        self.defaultTokenMetadata = uri;
    }  
    function setPrerevealTokenMetadataURI(FlexibleMetadataData storage self, string memory uri) public {
        self.prerevealTokenMetadata = uri;
    }  
    function setFlaggedTokenMetadataURI(FlexibleMetadataData storage self, string memory uri) public {
        self.flaggedTokenMetadata = uri;
    }  
    function setContractMetadataURI(FlexibleMetadataData storage self, string memory uri) public {
        self.contractMetadata = uri;
    }  
    function reveal(FlexibleMetadataData storage self, bool revealed) public {
        self.tokenReveal = revealed;
    }

    function flagToken(FlexibleMetadataData storage self, uint256 tokenId, bool flagged) public {
        self.tokenFlag[tokenId] = flagged;
    }

    function getTokenMetadata(FlexibleMetadataData storage self, uint256 tokenId) public view returns (string memory) {
        if (self.tokenFlag[tokenId]) {
            return encodeURI(self.flaggedTokenMetadata,tokenId);
        } 
        if (!self.tokenReveal) {
            return encodeURI(self.prerevealTokenMetadata,tokenId);
        }
        return encodeURI(self.defaultTokenMetadata,tokenId);
    }

    function getContractMetadata(FlexibleMetadataData storage self) public view returns (string memory) { 
        return self.contractMetadata;
    }    

    function encodeURI(string storage uri, uint256 tokenId) public pure returns (string memory) {
        return string(abi.encodePacked(uri, "/", toString(tokenId)));
    }

    function toString(uint256 value) public pure returns (string memory) {
        unchecked {
            uint256 length = 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), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    function log10(uint256 value) public 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;
    }        
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import { InvalidOwner } from "./SetOwnerEnumerable.sol";
struct LockableData { 

    mapping(address => uint256) lockableStatusIndex; 

    mapping(address => LockableStatus) lockableStatus;  
} 


struct LockableStatus {
    bool isLocked;
    uint256 lockedAt;
    address custodian;
    uint256 balance;
    address[] approvedAll;
    bool exists;
}

uint64 constant MAX_INT = 2**64 - 1;

error OnlyCustodianCanLock();

error OnlyOwnerCanSetCustodian();

error WalletLockedByOwner();


library SetLockable {           

    function lockWallet(LockableData storage self, address holder) public {
        LockableStatus storage status = self.lockableStatus[holder];    
        if (msg.sender != status.custodian) {
            revert OnlyCustodianCanLock();
        }       
        status.isLocked = true;
        status.lockedAt = block.timestamp;
    }

    function unlockWallet(LockableData storage self, address holder) public {        
        LockableStatus storage status = self.lockableStatus[holder];
        if (msg.sender != status.custodian) {
            revert OnlyCustodianCanLock();
        }                   
        
        status.isLocked = false;
        status.lockedAt = MAX_INT;
    }

    function setCustodian(LockableData storage self, address custodianAddress,  address holder) public {
        if (msg.sender != holder) {
            revert OnlyOwnerCanSetCustodian();
        }    
        LockableStatus storage status = self.lockableStatus[holder];
        status.custodian = custodianAddress;
    }

    function findCustodian(LockableData storage self, address wallet) public view returns (address) {
        return self.lockableStatus[wallet].custodian;
    }

    function forceUnlock(LockableData storage self, address owner) public {        
        LockableStatus storage status = self.lockableStatus[owner];
        status.isLocked = false;
        status.lockedAt = MAX_INT;
    }
            
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

struct OwnerEnumerableData { 
    mapping(uint256 => TokenOwnership) tokens;
    mapping(address => uint256[]) ownedTokens;

    mapping(address => mapping(uint256 => uint256)) ownedTokensIndex; 

    uint256 totalSupply;    
}    

struct TokenOwnership {
    address ownedBy;
    bool exists;
}

error TokenNonOwner(address requester, uint256 tokenId); 
error InvalidOwner();

library SetOwnerEnumerable {
    function addTokenToEnumeration(OwnerEnumerableData storage self, address to, uint256 tokenId) public {        
        self.ownedTokens[to].push(tokenId);        
        uint256 length = self.ownedTokens[to].length;
        self.ownedTokensIndex[to][tokenId] = length-1;
        self.tokens[tokenId] = TokenOwnership(to,true);
    }    

    function removeTokenFromEnumeration(OwnerEnumerableData storage self, address to, uint256 tokenId) public {

        uint256 length = self.ownedTokens[to].length;
        if (self.ownedTokensIndex[to][tokenId] > 0 && self.ownedTokensIndex[to][tokenId] != length - 1) {
            uint256 lastTokenId = self.ownedTokens[to][length - 1];
            self.ownedTokens[to][self.ownedTokensIndex[to][tokenId]] = lastTokenId; 
            self.ownedTokensIndex[to][lastTokenId] = self.ownedTokensIndex[to][tokenId];
        }

        delete self.ownedTokensIndex[to][tokenId];
        if (self.ownedTokens[to].length > 0) {
            self.ownedTokens[to].pop();
        }
    }    

    function findTokensOwned(OwnerEnumerableData storage self, address wallet) public view returns (uint256[] storage) {
        return self.ownedTokens[wallet];
    }  

    function tokenIndex(OwnerEnumerableData storage self, address wallet, uint256 index) public view returns (uint256) {
        return self.ownedTokens[wallet][index];
    }    

    function ownerOf(OwnerEnumerableData storage self, uint256 tokenId) public view returns (address) {
        address owner = self.tokens[tokenId].ownedBy;
        if (owner == address(0)) {
            revert TokenNonOwner(owner,tokenId);
        }
        return owner;
    }      
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
struct ReceivableData { 
    mapping(address => mapping(address => uint256[])) receivedTokens;

    mapping(address => address[]) stakedContracts;

    mapping(address => mapping(address => uint256)) stakedContractIndex;

    mapping(address => mapping(uint256 => uint256)) receivedTokensIndex;    
    
    mapping(address => mapping(address => uint256)) walletBalances;
} 

interface Holdable {
    function balanceOf(address owner) external returns (uint256);
    function ownerOf(uint256 tokenId) external returns (address);
}
error MintNotLive();

error ReceivedTokenNonExistent(uint256 tokenId);

error ReceivedTokenNonOwner(address requester, uint256 tokenId);  

library SetReceivable {    
 
    function balanceOfWallet(ReceivableData storage self, address wallet, address contracted) public view returns (uint256) {        
        return self.walletBalances[wallet][contracted];
    }

    function receivedFromWallet(ReceivableData storage self, address wallet, address contracted) public view returns (uint256[] memory) {        
        return self.receivedTokens[wallet][contracted];
    }    

    function _addTokenToReceivedEnumeration(ReceivableData storage self, address from, address contracted, uint256 tokenId) public {
        uint256 length = balanceOfWallet(self,from,contracted);
        
        if (length >= self.receivedTokens[from][contracted].length) {
            length = self.receivedTokens[from][contracted].length;
            self.receivedTokens[from][contracted].push(tokenId);
            // revert ReceivedTokenNonExistent(self.receivedTokens[from][contracted][0]);
        } else {
            self.receivedTokens[from][contracted][length] = tokenId;    
            
        }
        self.receivedTokensIndex[contracted][tokenId] = length;
        self.walletBalances[from][contracted]++;
        if (self.receivedTokens[from][contracted].length < 1) {
            revert ReceivedTokenNonExistent(tokenId);
        }     

        if (length < 1) {
            self.stakedContracts[from].push(contracted);
            self.stakedContractIndex[from][contracted] = self.stakedContracts[from].length;
        }    
    }    

    function _removeTokenFromReceivedEnumeration(ReceivableData storage self, address from, address contracted, uint256 tokenId) public {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).  

        // if (self.receivedTokens[from][contracted].length < 1) {
        //     revert ReceivedTokenNonExistent(tokenId);
        // }      

        // When the token to delete is the last token, the swap operation is unnecessary
        if (self.receivedTokens[from][contracted].length > self.receivedTokensIndex[contracted][tokenId] && 
        self.receivedTokensIndex[contracted][tokenId] != self.receivedTokens[from][contracted].length - 1) {
            uint256 lastTokenId = self.receivedTokens[from][contracted][balanceOfWallet(self,from,contracted) - 1];
            
            self.receivedTokens[from][contracted][self.receivedTokensIndex[contracted][tokenId]] = lastTokenId; // Move the last token to the slot of the to-delete token
            self.receivedTokensIndex[contracted][lastTokenId] = self.receivedTokensIndex[contracted][tokenId]; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete self.receivedTokensIndex[contracted][tokenId];
        self.receivedTokens[from][contracted].pop();
        self.walletBalances[from][contracted]--;

        uint256 left = balanceOfWallet(self,from,contracted);

        if (left < 1) {
            if (self.stakedContracts[from].length > self.stakedContractIndex[from][contracted] && 
                self.stakedContractIndex[from][contracted] != self.stakedContracts[from].length - 1) {
                
                address lastContract = self.stakedContracts[from][self.stakedContracts[from].length - 1];

                self.stakedContracts[from][self.stakedContracts[from].length - 1] = contracted;
                self.stakedContracts[from][self.stakedContractIndex[from][contracted]] = lastContract;                
            }

            self.stakedContracts[from].pop();
            delete self.stakedContractIndex[from][contracted];
        } 
    }    

    function tokenReceivedByIndex(ReceivableData storage self, address wallet, address contracted, uint256 index) public view returns (uint256) {
        return self.receivedTokens[wallet][contracted][index];
    }    

    function swapOwner(ReceivableData storage self, address from, address to) public {
        for (uint256 contractIndex = 0; contractIndex < self.stakedContracts[from].length; contractIndex++) {
            address contractToSwap = self.stakedContracts[from][contractIndex];
            
            uint256 tokenId = self.receivedTokens[from][contractToSwap][0];
            while (self.receivedTokens[from][contractToSwap].length > 0) {
                _removeTokenFromReceivedEnumeration(self,from,contractToSwap,tokenId);
                _addTokenToReceivedEnumeration(self,to,contractToSwap,tokenId);
                if ((self.receivedTokens[from][contractToSwap].length > 0)) {
                    tokenId = self.receivedTokens[from][contractToSwap][0];
                }
            }
        }
    }

    function withdraw(ReceivableData storage self, address contracted, uint256[] calldata tokenIds) public {        
        for (uint256 i; i < tokenIds.length; i++) {
            uint256 tokenId = tokenIds[i];
            Holdable held = Holdable(contracted);
            if (held.ownerOf(tokenId) != address(this)) {
                revert ReceivedTokenNonOwner(address(this),tokenId);
            }
            // uint256 tokenIndex = self.receivedTokensIndex[contracted][tokenId];
            // if (self.receivedTokens[msg.sender][contracted].length > tokenIndex &&
            //     tokenReceivedByIndex(self,msg.sender,contracted,tokenIndex) != tokenId) {
            //     revert ReceivedTokenNonOwner(msg.sender,tokenIndex);
            // }            
            _removeTokenFromReceivedEnumeration(self,msg.sender,contracted,tokenId);
            IERC721(contracted).safeTransferFrom(
                address(this),
                msg.sender,
                tokenId,
                ""
            );
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

struct SubscriptionSpans {
    uint256 one;
    uint256 three;
    uint256 six;
    uint256 twelve;
}

struct FeeStructure {
    uint256 baseMultiplier;
    uint256 baseDiscount;
    uint256 annual;
}

struct PromoDiscount {
    uint256 amount;
    uint256 commission;
    uint256 timesUsed;
    uint256 expires;
    address partner;
    bool exists;
}

struct SubscribableData { 
    // day number to rate
    // mapping(uint256 => RateStructure) spanToRate;
    // tokenId to expiration
    mapping(uint256 => uint256) subscriptions;
    mapping(string => PromoDiscount) promoDiscounts;
    SubscriptionSpans subscriptionSpans;
    FeeStructure feeStructure;
}    

error InvalidNumberOfDays(uint256 numberOfDays);
error InvalidAmountForDays(uint256 numberOfDays, uint256 amount, uint256 required);
error DiscountIsInvalid(string discountCode);

address constant defaultPayable = 0x5aE09f46967A92f3cF976e98f82B6FDd00784815;
string constant blank = " ";
uint256 constant never = 9999999999999999999999999999;

library SetSubscribable {

    event SubscriptionUpdate(uint256 indexed tokenId, uint256 expiration);
       
    function initialize(SubscribableData storage self) public {
        setSpans(self, 4 * 7, 12 * 7, 24 * 7, 48 * 7); // 4 weeks, 12 weeks, 24 weeks, 48 weeks
        setFeeStructure(self,4, 25, 52); // base multiplier, base discount, annual period
        self.promoDiscounts[blank] = PromoDiscount(0,0,0,never,defaultPayable,true);
    }

    function setSpans(SubscribableData storage self, uint256 one, uint256 three, uint256 six, uint256 twelve) public {
        self.subscriptionSpans = SubscriptionSpans(one,three,six,twelve);
    }

    function setFeeStructure(SubscribableData storage self, uint256 multiplier, uint256 discount, uint256 annual) public {
        self.feeStructure =  FeeStructure(multiplier,discount,annual);                
    }    

    function setRateParams(SubscribableData storage self, uint256 multiplier, uint256 discount) public {
        setSpans(self,28, 84, 168, 336);
        setFeeStructure(self,multiplier, discount, 52);
    }

    function establishSubscription(SubscribableData storage self, uint256 tokenId, uint256 numberOfDays) public {
        uint256 expiration;
        if (block.timestamp > self.subscriptions[tokenId]) {
            expiration = block.timestamp + numberOfDays * 1 days;
        } else {
            expiration = self.subscriptions[tokenId] + numberOfDays * 1 days;
        }        
        self.subscriptions[tokenId] = expiration;
        emit SubscriptionUpdate(tokenId, expiration);
    }      
    
    function calculateExpiration(SubscribableData storage self, uint256 tokenId, uint256 numberOfDays) public view returns (uint256) {
        if (block.timestamp > self.subscriptions[tokenId]) {
            return block.timestamp + numberOfDays * 1 days;
        } 
        return self.subscriptions[tokenId] + numberOfDays * 1 days;                     
    }

    function calculateBaseRate(SubscribableData storage self, uint256 numberOfDays) public view returns (uint256) {
        uint256 discountMultiplier = numberOfDays == self.subscriptionSpans.one ? 0 :
        numberOfDays == self.subscriptionSpans.three ? 1 :
        numberOfDays == self.subscriptionSpans.six ? 2 :
        3;

        uint256 spans = numberOfDays / 7;

        uint256 periodDiscount = discountMultiplier * self.feeStructure.baseDiscount * (1 ether);

        return ((self.feeStructure.baseMultiplier * 100 * (1 ether)) - periodDiscount) / 100 / self.feeStructure.annual * spans;
    } 

    function calculateDiscount(uint256 promoDiscount) public pure returns (uint256) {
        return 100-promoDiscount;
    }         

    function calculateFee(SubscribableData storage self, uint256 numberOfDays) public view returns (uint256) {    
        return calculateFee(self, numberOfDays, blank);                                           
    }   

    function calculateFee(SubscribableData storage self, uint256 numberOfDays, string memory discountCode) public view returns (uint256) {

        validateDays(self,numberOfDays);        

        uint256 baseRate = calculateBaseRate(self,numberOfDays);

        uint256 discount = calculateDiscount(self.promoDiscounts[discountCode].amount);

        baseRate = baseRate * discount / 100;

        return floor(baseRate);        
    }       
    function calculateCommission(SubscribableData storage self, uint256 originalAmount, string memory discountCode) public view returns (uint256) {
        uint256 commissionRate = self.promoDiscounts[discountCode].commission > 0 ? 10000/self.promoDiscounts[discountCode].commission : 0;
        
        uint256 commission = 0;
        if (commissionRate >= 1) {
            commission = originalAmount / commissionRate * 100;            
        }     

        return commission;      
    }         
      
    function validateDays(SubscribableData storage self, uint256 numberOfDays) public view {
        if (numberOfDays != self.subscriptionSpans.one &&
            numberOfDays != self.subscriptionSpans.three && 
            numberOfDays != self.subscriptionSpans.six && 
            numberOfDays != self.subscriptionSpans.twelve ) {
            revert InvalidNumberOfDays(numberOfDays);
        }
    }

    function validatePayment(SubscribableData storage self, uint256 numberOfDays, string memory promoDiscount) public view {        
        uint256 cost = calculateFee(self, numberOfDays, promoDiscount);
        
        if (msg.value != cost) {
            revert InvalidAmountForDays(numberOfDays, msg.value, cost);
        }
    }

    function validateSubscription(SubscribableData storage self, uint256 numberOfDays, string calldata discountCode) public view {
        validateDays(self,numberOfDays);
        validatePayment(self,numberOfDays,discountCode);
    }    

    function validateSubscription(SubscribableData storage self, uint256 numberOfDays) public view {
        validateDays(self,numberOfDays);
        validatePayment(self,numberOfDays,blank);
    }     

    function floor(uint256 amount) public pure returns (uint256) {        
        return amount - (amount % 10000000000000000);
    }

    function expiresAt(SubscribableData storage self, uint256 tokenId) public view returns(uint256) {
        return self.subscriptions[tokenId];
    }

}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./Contractable.sol";
import "./FlexibleMetadata.sol";
import {SetSubscribable, SubscribableData, PromoDiscount, defaultPayable, InvalidNumberOfDays } from "./SetSubscribable.sol";

abstract contract Subscribable is Contractable {
    using SetSubscribable for SubscribableData; // this is the crucial change
    SubscribableData subs;

    string constant blank = " ";

    address payable internal OSM_TREASURY_WALLET = payable(defaultPayable);

    constructor(string memory name, string memory symbol) FlexibleMetadata(name,symbol) {
        subs.initialize();
    }  

    function standardFee(uint256 numberOfDays) public view returns (uint256) {
        return subs.calculateFee(numberOfDays);        
    }     

    function determineFee(uint256 numberOfDays, string memory discountCode) public view returns (uint256) {
        return subs.calculateFee(numberOfDays,discountCode);        
    }      

    function determineCommission(uint256 amount, string memory discountCode) public view returns (uint256) {
        return subs.calculateCommission(amount,discountCode);
    }

    function floor(uint256 amount) internal pure returns (uint256) {
        return amount - (amount % 1000000000000000);
    }

    function expiresAt(uint256 tokenId) external view returns (uint256) {
        return subs.expiresAt(tokenId);
    }

    function setRecipient(address recipient) external onlyOwner {        
        OSM_TREASURY_WALLET = payable(recipient);    
    }

    function addPromoDiscount(string calldata discountCode, uint256 amount, uint256 commission, address partner) external onlyOwner {    
        subs.promoDiscounts[discountCode] = PromoDiscount(amount,commission,0,block.timestamp + (4 * 7 days),partner,true);
    }   

    function getPromoDiscount(string calldata discountCode) external view returns (PromoDiscount memory) {    
        return subs.promoDiscounts[discountCode];
    }       

    function setRateParams(uint256 multiplier, uint256 discount) external onlyOwner {
        subs.setRateParams(multiplier,discount);
    }

    function commitSubscription(uint256 tokenId, uint numberOfDays) internal {
        commitSubscription(tokenId, numberOfDays, blank);      
    }

    function establishSubscription(uint256 tokenId, uint numberOfDays) internal {
        subs.establishSubscription(tokenId, numberOfDays);      
    }    
    
    function commitSubscription(uint256 tokenId, uint numberOfDays, string memory discountCode) internal {
        subs.validateSubscription(numberOfDays,discountCode);
        subs.establishSubscription(tokenId,numberOfDays);        
    }

    function renewSubscription(uint256 tokenId, uint numberOfDays, string memory discountCode) internal {
        validateApprovedOrOwner(msg.sender, tokenId);
        subs.validateSubscription(numberOfDays, discountCode);
        commitSubscription(tokenId, numberOfDays, discountCode);
    }

    function isRenewable(uint256 tokenId) external view returns(bool) {
        return exists(tokenId);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "./Subscribable.sol";
import "./LockableTransferrable.sol";
import { SetReceivable, ReceivableData, ReceivedTokenNonExistent, ReceivedTokenNonOwner, MintNotLive } from "./SetReceivable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/Address.sol";

error ReceiverNotImplemented();

abstract contract TokenReceiver is Subscribable,IERC721Receiver {
    using Address for address;
    using SetReceivable for ReceivableData; // this is the crucial change
    ReceivableData receivables;
      

    function balanceOfWallet(address wallet, address contracted) public view returns (uint256) {
        return receivables.balanceOfWallet(wallet,contracted);
    }  

    function hasReceived(address wallet, address contracted) public view returns (uint256[] memory) {
        return receivables.receivedFromWallet(wallet,contracted);
    }

    function _addTokenToReceivedEnumeration(address from, address contracted, uint256 tokenId) private {
        receivables._addTokenToReceivedEnumeration(from,contracted,tokenId);
    }    

    function _removeTokenFromReceivedEnumeration(address from, address contracted, uint256 tokenId) private {
        receivables._removeTokenFromReceivedEnumeration(from,contracted,tokenId);
    }

    function tokenReceivedByIndex(address wallet, address contracted, uint256 index) public view returns (uint256) {
        return receivables.tokenReceivedByIndex(wallet,contracted,index);
    }

    function withdraw(address contracted, uint256[] calldata tokenIds) public {
        return receivables.withdraw(contracted,tokenIds);
    }
 
    function onERC721Received(address, address from, uint256 tokenId, bytes memory) public virtual override returns (bytes4) {
        _addTokenToReceivedEnumeration(from, msg.sender, tokenId);
        return this.onERC721Received.selector;
    }     

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        super.safeTransferFrom(from, to, tokenId, "");
        receivables.swapOwner(from,to);
    }   

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        super.transferFrom(from, to, tokenId);
        receivables.swapOwner(from,to);
    }
     
}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {
    "contracts/OSM/SetApprovable.sol": {
      "SetApprovable": "0xd44fc4f2f36e6a75bca189001f2b243dbc7a0d12"
    },
    "contracts/OSM/SetContractable.sol": {
      "SetContractable": "0x2008152272e4678d4661891125a070e4c3e5edc8"
    },
    "contracts/OSM/SetFlexibleMetadata.sol": {
      "SetFlexibleMetadataData": "0xc4a3392eb009a88e9a8b4101587a1a7bcf804326"
    },
    "contracts/OSM/SetLockable.sol": {
      "SetLockable": "0x1b7b48434d041eede56b532f2542ac3e1df42dba"
    },
    "contracts/OSM/SetOwnerEnumerable.sol": {
      "SetOwnerEnumerable": "0xf7efe8f7f017b7eba93daab7c7518e6a4f90bf2e"
    },
    "contracts/OSM/SetReceivable.sol": {
      "SetReceivable": "0x17e46924e6e004c5618bca34feb32c14d55fce51"
    },
    "contracts/OSM/SetSubscribable.sol": {
      "SetSubscribable": "0xa1f273011d271ec06d35b7e731e7f899391cd9b0"
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotOwner","type":"error"},{"inputs":[],"name":"ContractIsNot721Receiver","type":"error"},{"inputs":[{"internalType":"string","name":"discountCode","type":"string"}],"name":"DiscountIsInvalid","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"zero","type":"address"}],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidTransferRecipient","type":"error"},{"inputs":[],"name":"MintIsNotLive","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"OnlyOneSubscriptionPerWallet","type":"error"},{"inputs":[],"name":"OwnerCannotBeZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenAlreadyMinted","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenNonExistent","type":"error"},{"inputs":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenNonOwner","type":"error"},{"inputs":[],"name":"WalletLockedByOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CommissionPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"string","name":"discountCode","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"commission","type":"uint256"},{"internalType":"address","name":"partner","type":"address"}],"name":"addPromoDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"allowed","type":"address"},{"internalType":"string","name":"urlPath","type":"string"},{"internalType":"string","name":"erc","type":"string"},{"internalType":"uint256","name":"balanceRequired","type":"uint256"},{"internalType":"bool","name":"isStaking","type":"bool"},{"internalType":"bool","name":"isProxy","type":"bool"}],"name":"allowContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"allowances","outputs":[{"components":[{"internalType":"address","name":"addressed","type":"address"},{"internalType":"string","name":"urlPath","type":"string"},{"internalType":"string","name":"erc","type":"string"},{"internalType":"uint256","name":"balanceRequired","type":"uint256"},{"internalType":"bool","name":"isStaking","type":"bool"},{"internalType":"bool","name":"isProxy","type":"bool"},{"internalType":"bool","name":"exists","type":"bool"}],"internalType":"struct AllowedContract[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"balanceOfAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"contracted","type":"address"}],"name":"balanceOfWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"custodianOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"discountCode","type":"string"}],"name":"determineCommission","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfDays","type":"uint256"},{"internalType":"string","name":"discountCode","type":"string"}],"name":"determineFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfDays","type":"uint256"},{"internalType":"string","name":"discountCode","type":"string"}],"name":"discountMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"expiresAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"discountCode","type":"string"}],"name":"getPromoDiscount","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"commission","type":"uint256"},{"internalType":"uint256","name":"timesUsed","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"internalType":"address","name":"partner","type":"address"},{"internalType":"bool","name":"exists","type":"bool"}],"internalType":"struct PromoDiscount","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"contracted","type":"address"}],"name":"hasReceived","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isRenewable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"lockWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"lockedSince","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfDays","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"numberOfDays","type":"uint256"}],"name":"mintForRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"path","type":"string"}],"name":"pathAllows","outputs":[{"components":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"address","name":"wallet","type":"address"},{"internalType":"bool","name":"exists","type":"bool"}],"internalType":"struct AllowedPath","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numberOfDays","type":"uint256"},{"internalType":"string","name":"discountCode","type":"string"}],"name":"renewOSM","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numberOfDays","type":"uint256"}],"name":"renewOSM","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_reveal","type":"bool"}],"name":"reveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"revoked","type":"address"}],"name":"revokeContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","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":"uri","type":"string"}],"name":"setContractUri","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"custodianAddress","type":"address"}],"name":"setCustodian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isLive","type":"bool"}],"name":"setMintLive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint256","name":"discount","type":"uint256"}],"name":"setRateParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"setRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"},{"internalType":"uint256","name":"tokenType","type":"uint256"}],"name":"setTokenUri","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfDays","type":"uint256"}],"name":"standardFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"contracted","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenReceivedByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"tokensOwnedBy","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unlockWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contracted","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052735ae09f46967a92f3cf976e98f82b6fdd00784815602660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503480156200006657600080fd5b50604051620063863803806200638683398181016040528101906200008c919062000396565b81818181620000a1336200013f60201b60201c565b8160079081620000b2919062000666565b508060089081620000c4919062000666565b505050601d73a1f273011d271ec06d35b7e731e7f899391cd9b0639bc21dba90916040518263ffffffff1660e01b815260040162000103919062000754565b60006040518083038186803b1580156200011c57600080fd5b505af415801562000131573d6000803e3d6000fd5b505050505050505062000771565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200026c8262000221565b810181811067ffffffffffffffff821117156200028e576200028d62000232565b5b80604052505050565b6000620002a362000203565b9050620002b1828262000261565b919050565b600067ffffffffffffffff821115620002d457620002d362000232565b5b620002df8262000221565b9050602081019050919050565b60005b838110156200030c578082015181840152602081019050620002ef565b60008484015250505050565b60006200032f6200032984620002b6565b62000297565b9050828152602081018484840111156200034e576200034d6200021c565b5b6200035b848285620002ec565b509392505050565b600082601f8301126200037b576200037a62000217565b5b81516200038d84826020860162000318565b91505092915050565b60008060408385031215620003b057620003af6200020d565b5b600083015167ffffffffffffffff811115620003d157620003d062000212565b5b620003df8582860162000363565b925050602083015167ffffffffffffffff81111562000403576200040262000212565b5b620004118582860162000363565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200046e57607f821691505b60208210810362000484576200048362000426565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620004ee7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620004af565b620004fa8683620004af565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600062000547620005416200053b8462000512565b6200051c565b62000512565b9050919050565b6000819050919050565b620005638362000526565b6200057b62000572826200054e565b848454620004bc565b825550505050565b600090565b6200059262000583565b6200059f81848462000558565b505050565b5b81811015620005c757620005bb60008262000588565b600181019050620005a5565b5050565b601f8211156200061657620005e0816200048a565b620005eb846200049f565b81016020851015620005fb578190505b620006136200060a856200049f565b830182620005a4565b50505b505050565b600082821c905092915050565b60006200063b600019846008026200061b565b1980831691505092915050565b600062000656838362000628565b9150826002028217905092915050565b62000671826200041b565b67ffffffffffffffff8111156200068d576200068c62000232565b5b62000699825462000455565b620006a6828285620005cb565b600060209050601f831160018114620006de5760008415620006c9578287015190505b620006d5858262000648565b86555062000745565b601f198416620006ee866200048a565b60005b828110156200071857848901518255600182019150602085019450602081019050620006f1565b8683101562000738578489015162000734601f89168262000628565b8355505b6001600288020188555050505b505050505050565b8082525050565b60006020820190506200076b60008301846200074d565b92915050565b615c0580620007816000396000f3fe60806040526004361061031a5760003560e01c8063937506f8116101ab578063c87b56dd116100f7578063de3efc9111610095578063ea66aeb31161006f578063ea66aeb314610c6d578063f2fde38b14610caa578063f6aacfb114610cd3578063fbd6a8af14610d105761031a565b8063de3efc9114610bc8578063e8a3d48514610c05578063e985e9c514610c305761031a565b8063cde317af116100d1578063cde317af14610b10578063cf41175914610b4d578063d480924d14610b76578063d6cd022e14610b9f5761031a565b8063c87b56dd14610a81578063cc2e3ee114610abe578063ccb4807b14610ae75761031a565b8063a2cd995d11610164578063af6f26cd1161013e578063af6f26cd146109b5578063b88d4fde146109f2578063ba4b62bf14610a1b578063bebd74ad14610a585761031a565b8063a2cd995d1461091f578063a9c133c71461095c578063ae38b5cf146109995761031a565b8063937506f81461080c578063940cd05b1461084957806395d89b4114610872578063a0712d681461089d578063a1a39af2146108b9578063a22cb465146108f65761031a565b806342842e0e1161026a57806370a08231116102235780638293744b116101fd5780638293744b1461075257806389cea3dd1461077b5780638da5cb5b146107b8578063911c9874146107e35761031a565b806370a08231146106c1578063715018a6146106fe57806380b9b855146107155761031a565b806342842e0e146105a357806353ca912a146105cc5780636264cc4e146105f55780636352211e146106325780636500d4111461066f5780636afc1334146106985761031a565b806318160ddd116102d75780632de409f3116102b15780632de409f3146104f857806335ca1c79146105355780633912928a1461055e5780633bbed4a01461057a5761031a565b806318160ddd1461046757806323b872dd146104925780632b603c71146104bb5761031a565b806301ffc9a71461031f57806306fdde031461035c578063081812fc14610387578063095ea7b3146103c4578063150b7a02146103ed57806317c957091461042a575b600080fd5b34801561032b57600080fd5b5061034660048036038101906103419190613bbc565b610d2c565b6040516103539190613c04565b60405180910390f35b34801561036857600080fd5b50610371610e0e565b60405161037e9190613caf565b60405180910390f35b34801561039357600080fd5b506103ae60048036038101906103a99190613d07565b610ea0565b6040516103bb9190613d75565b60405180910390f35b3480156103d057600080fd5b506103eb60048036038101906103e69190613dbc565b610eec565b005b3480156103f957600080fd5b50610414600480360381019061040f9190613f31565b610f03565b6040516104219190613fc3565b60405180910390f35b34801561043657600080fd5b50610451600480360381019061044c9190613d07565b610f22565b60405161045e9190613fed565b60405180910390f35b34801561047357600080fd5b5061047c610fa8565b6040516104899190613fed565b60405180910390f35b34801561049e57600080fd5b506104b960048036038101906104b49190614008565b610fb2565b005b3480156104c757600080fd5b506104e260048036038101906104dd919061405b565b611030565b6040516104ef9190614264565b60405180910390f35b34801561050457600080fd5b5061051f600480360381019061051a91906142e6565b6110bb565b60405161052c9190614432565b60405180910390f35b34801561054157600080fd5b5061055c60048036038101906105579190613d07565b61114f565b005b610578600480360381019061057391906144f5565b6111c6565b005b34801561058657600080fd5b506105a1600480360381019061059c919061405b565b6111e0565b005b3480156105af57600080fd5b506105ca60048036038101906105c59190614008565b61122c565b005b3480156105d857600080fd5b506105f360048036038101906105ee9190614590565b6112ba565b005b34801561060157600080fd5b5061061c60048036038101906106179190614008565b6112df565b6040516106299190613fed565b60405180910390f35b34801561063e57600080fd5b5061065960048036038101906106549190613d07565b61136b565b6040516106669190613d75565b60405180910390f35b34801561067b57600080fd5b50610696600480360381019061069191906145bd565b6113f1565b005b3480156106a457600080fd5b506106bf60048036038101906106ba9190613d07565b611475565b005b3480156106cd57600080fd5b506106e860048036038101906106e3919061405b565b6114fb565b6040516106f59190613fed565b60405180910390f35b34801561070a57600080fd5b50610713611553565b005b34801561072157600080fd5b5061073c6004803603810190610737919061468c565b611567565b6040516107499190613fed565b60405180910390f35b34801561075e57600080fd5b506107796004803603810190610774919061473e565b6115ef565b005b34801561078757600080fd5b506107a2600480360381019061079d919061405b565b611664565b6040516107af9190613fed565b60405180910390f35b3480156107c457600080fd5b506107cd6116ea565b6040516107da9190613d75565b60405180910390f35b3480156107ef57600080fd5b5061080a6004803603810190610805919061479e565b611713565b005b34801561081857600080fd5b50610833600480360381019061082e91906147de565b61178d565b6040516108409190613fed565b60405180910390f35b34801561085557600080fd5b50610870600480360381019061086b9190614590565b611816565b005b34801561087e57600080fd5b5061088761188d565b6040516108949190613caf565b60405180910390f35b6108b760048036038101906108b29190613d07565b61191f565b005b3480156108c557600080fd5b506108e060048036038101906108db9190613d07565b61196b565b6040516108ed9190613fed565b60405180910390f35b34801561090257600080fd5b5061091d6004803603810190610918919061481e565b6119c2565b005b34801561092b57600080fd5b50610946600480360381019061094191906142e6565b6119fc565b60405161095391906148d9565b60405180910390f35b34801561096857600080fd5b50610983600480360381019061097e91906147de565b611ad3565b60405161099091906149a3565b60405180910390f35b6109b360048036038101906109ae91906149c5565b611b61565b005b3480156109c157600080fd5b506109dc60048036038101906109d7919061468c565b611ba5565b6040516109e99190613fed565b60405180910390f35b3480156109fe57600080fd5b50610a196004803603810190610a149190613f31565b611c2e565b005b348015610a2757600080fd5b50610a426004803603810190610a3d9190613d07565b611c53565b604051610a4f9190613fed565b60405180910390f35b348015610a6457600080fd5b50610a7f6004803603810190610a7a9190614a05565b611cd9565b005b348015610a8d57600080fd5b50610aa86004803603810190610aa39190613d07565b611df2565b604051610ab59190613caf565b60405180910390f35b348015610aca57600080fd5b50610ae56004803603810190610ae0919061405b565b611e7d565b005b348015610af357600080fd5b50610b0e6004803603810190610b099190614a8d565b611eec565b005b348015610b1c57600080fd5b50610b376004803603810190610b329190613d07565b611f63565b604051610b449190613c04565b60405180910390f35b348015610b5957600080fd5b50610b746004803603810190610b6f9190613dbc565b611f75565b005b348015610b8257600080fd5b50610b9d6004803603810190610b989190614ad6565b611f93565b005b348015610bab57600080fd5b50610bc66004803603810190610bc191906149c5565b6120f7565b005b348015610bd457600080fd5b50610bef6004803603810190610bea9190613d07565b612171565b604051610bfc9190613d75565b60405180910390f35b348015610c1157600080fd5b50610c1a6121ff565b604051610c279190613caf565b60405180910390f35b348015610c3c57600080fd5b50610c576004803603810190610c5291906147de565b612286565b604051610c649190613c04565b60405180910390f35b348015610c7957600080fd5b50610c946004803603810190610c8f919061405b565b61230f565b604051610ca191906149a3565b60405180910390f35b348015610cb657600080fd5b50610cd16004803603810190610ccc919061405b565b6123e4565b005b348015610cdf57600080fd5b50610cfa6004803603810190610cf59190613d07565b61245e565b604051610d079190613c04565b60405180910390f35b610d2a6004803603810190610d259190614b32565b6124c2565b005b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610df757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610e075750610e068261266a565b5b9050919050565b606060078054610e1d90614bc1565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4990614bc1565b8015610e965780601f10610e6b57610100808354040283529160200191610e96565b820191906000526020600020905b815481529060010190602001808311610e7957829003601f168201915b5050505050905090565b6000610eab826126d4565b600d600601600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b610ef581612721565b610eff8282612764565b5050565b6000610f108433856128b3565b63150b7a0260e01b9050949350505050565b6000601d73a1f273011d271ec06d35b7e731e7f899391cd9b06347f5a81c9091846040518363ffffffff1660e01b8152600401610f60929190614c08565b602060405180830381865af4158015610f7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa19190614c46565b9050919050565b6000601854905090565b610fbd838383612928565b60277317e46924e6e004c5618bca34feb32c14d55fce51636e520c42909185856040518463ffffffff1660e01b8152600401610ffb93929190614c89565b60006040518083038186803b15801561101357600080fd5b505af4158015611027573d6000803e3d6000fd5b50505050505050565b60606019732008152272e4678d4661891125a070e4c3e5edc86308ce42cc9091846040518363ffffffff1660e01b815260040161106e929190614cc7565b600060405180830381865af415801561108b573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906110b49190614f61565b9050919050565b6110c3613a22565b6019732008152272e4678d4661891125a070e4c3e5edc863fd16883c909185856040518463ffffffff1660e01b815260040161110193929190614fe8565b600060405180830381865af415801561111e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611147919061515d565b905092915050565b6015731b7b48434d041eede56b532f2542ac3e1df42dba638fb14e3b90916111768461136b565b6040518363ffffffff1660e01b81526004016111939291906151ad565b60006040518083038186803b1580156111ab57600080fd5b505af41580156111bf573d6000803e3d6000fd5b5050505050565b6111d0828261294b565b6111db838383612b52565b505050565b6111e8612bda565b80602660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61124783838360405180602001604052806000815250611c2e565b60277317e46924e6e004c5618bca34feb32c14d55fce51636e520c42909185856040518463ffffffff1660e01b815260040161128593929190614c89565b60006040518083038186803b15801561129d57600080fd5b505af41580156112b1573d6000803e3d6000fd5b50505050505050565b6112c2612bda565b80601760006101000a81548160ff02191690831515021790555050565b600060277317e46924e6e004c5618bca34feb32c14d55fce51635908f8e590918686866040518563ffffffff1660e01b815260040161132194939291906151d6565b602060405180830381865af415801561133e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113629190614c46565b90509392505050565b6000600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e630266c7a39091846040518363ffffffff1660e01b81526004016113a9929190615222565b602060405180830381865af41580156113c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ea919061524b565b9050919050565b6019732008152272e4678d4661891125a070e4c3e5edc8639895d47d90918a8a8a8a8a8a8a8a6040518a63ffffffff1660e01b815260040161143b99989796959493929190615287565b60006040518083038186803b15801561145357600080fd5b505af4158015611467573d6000803e3d6000fd5b505050505050505050505050565b60006114808261136b565b905061148b81612c53565b6015731b7b48434d041eede56b532f2542ac3e1df42dba63b04686629091836040518363ffffffff1660e01b81526004016114c79291906151ad565b60006040518083038186803b1580156114df57600080fd5b505af41580156114f3573d6000803e3d6000fd5b505050505050565b600061150682612ccc565b600960010160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b61155b612bda565b6115656000612d35565b565b6000601d73a1f273011d271ec06d35b7e731e7f899391cd9b0629c1dd4909185856040518463ffffffff1660e01b81526004016115a693929190615341565b602060405180830381865af41580156115c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e79190614c46565b905092915050565b60277317e46924e6e004c5618bca34feb32c14d55fce51634412be0090918585856040518563ffffffff1660e01b815260040161162f94939291906153fa565b60006040518083038186803b15801561164757600080fd5b505af415801561165b573d6000803e3d6000fd5b50505050505050565b60006019732008152272e4678d4661891125a070e4c3e5edc86373632d479091846040518363ffffffff1660e01b81526004016116a2929190614cc7565b602060405180830381865af41580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e39190614c46565b9050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6015731b7b48434d041eede56b532f2542ac3e1df42dba6311841d7090918361173b8661136b565b6040518463ffffffff1660e01b81526004016117599392919061543a565b60006040518083038186803b15801561177157600080fd5b505af4158015611785573d6000803e3d6000fd5b505050505050565b600060277317e46924e6e004c5618bca34feb32c14d55fce5163c412a736909185856040518463ffffffff1660e01b81526004016117cd93929190614c89565b602060405180830381865af41580156117ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180e9190614c46565b905092915050565b61181e612bda565b600173c4a3392eb009a88e9a8b4101587a1a7bcf80432663da1542a69091836040518363ffffffff1660e01b815260040161185a929190615478565b60006040518083038186803b15801561187257600080fd5b505af4158015611886573d6000803e3d6000fd5b5050505050565b60606008805461189c90614bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546118c890614bc1565b80156119155780601f106118ea57610100808354040283529160200191611915565b820191906000526020600020905b8154815290600101906020018083116118f857829003601f168201915b5050505050905090565b61195e816040518060400160405280600181526020017f200000000000000000000000000000000000000000000000000000000000000081525061294b565b6119683382612df9565b50565b60006015600101600061197d8461136b565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101549050919050565b6119ee6119ce3361230f565b6000815181106119e1576119e06154a1565b5b6020026020010151612721565b6119f88282612e3d565b5050565b611a04613a5b565b601d6001018383604051611a19929190615500565b90815260200160405180910390206040518060c0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016004820160149054906101000a900460ff161515151581525050905092915050565b606060277317e46924e6e004c5618bca34feb32c14d55fce5163c680a5c1909185856040518463ffffffff1660e01b8152600401611b1393929190614c89565b600060405180830381865af4158015611b30573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611b5991906155dc565b905092915050565b611ba182826040518060400160405280600181526020017f20000000000000000000000000000000000000000000000000000000000000008152506111c6565b5050565b6000601d73a1f273011d271ec06d35b7e731e7f899391cd9b063967cf8d1909185856040518463ffffffff1660e01b8152600401611be593929190615341565b602060405180830381865af4158015611c02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c269190614c46565b905092915050565b611c383383612f27565b611c4182612721565b611c4d8484848461306e565b50505050565b6000601d73a1f273011d271ec06d35b7e731e7f899391cd9b063db48b3009091846040518363ffffffff1660e01b8152600401611c91929190614c08565b602060405180830381865af4158015611cae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd29190614c46565b9050919050565b611ce1612bda565b6040518060c00160405280848152602001838152602001600081526020016224ea0042611d0e9190615654565b81526020018273ffffffffffffffffffffffffffffffffffffffff16815260200160011515815250601d6001018686604051611d4b929190615500565b90815260200160405180910390206000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160040160146101000a81548160ff0219169083151502179055509050505050505050565b6060600173c4a3392eb009a88e9a8b4101587a1a7bcf80432663d30eae479091846040518363ffffffff1660e01b8152600401611e30929190615688565b600060405180830381865af4158015611e4d573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611e7691906156b1565b9050919050565b6019732008152272e4678d4661891125a070e4c3e5edc863b81093009091836040518363ffffffff1660e01b8152600401611eb9929190614cc7565b60006040518083038186803b158015611ed157600080fd5b505af4158015611ee5573d6000803e3d6000fd5b5050505050565b611ef4612bda565b600173c4a3392eb009a88e9a8b4101587a1a7bcf804326632d5459e29091836040518363ffffffff1660e01b8152600401611f309291906156fa565b60006040518083038186803b158015611f4857600080fd5b505af4158015611f5c573d6000803e3d6000fd5b5050505050565b6000611f6e826130c1565b9050919050565b611f7d612bda565b611f8f611f89836130f1565b8261311d565b5050565b6002810361200c57600173c4a3392eb009a88e9a8b4101587a1a7bcf80432663db6a3cab9091846040518363ffffffff1660e01b8152600401611fd79291906156fa565b60006040518083038186803b158015611fef57600080fd5b505af4158015612003573d6000803e3d6000fd5b505050506120f3565b6003810361208557600173c4a3392eb009a88e9a8b4101587a1a7bcf8043266348b5a5a39091846040518363ffffffff1660e01b81526004016120509291906156fa565b60006040518083038186803b15801561206857600080fd5b505af415801561207c573d6000803e3d6000fd5b505050506120f2565b600173c4a3392eb009a88e9a8b4101587a1a7bcf804326638bebb5869091846040518363ffffffff1660e01b81526004016120c19291906156fa565b60006040518083038186803b1580156120d957600080fd5b505af41580156120ed573d6000803e3d6000fd5b505050505b5b5050565b6120ff612bda565b601d73a1f273011d271ec06d35b7e731e7f899391cd9b0637ca5f858909184846040518463ffffffff1660e01b815260040161213d9392919061572a565b60006040518083038186803b15801561215557600080fd5b505af4158015612169573d6000803e3d6000fd5b505050505050565b60006015731b7b48434d041eede56b532f2542ac3e1df42dba63f1650c05909161219a8561136b565b6040518363ffffffff1660e01b81526004016121b79291906151ad565b602060405180830381865af41580156121d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f8919061524b565b9050919050565b6060600173c4a3392eb009a88e9a8b4101587a1a7bcf804326636ae383de90916040518263ffffffff1660e01b815260040161223b9190615761565b600060405180830381865af4158015612258573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061228191906156b1565b905090565b6000600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263e4e0a723909185856040518463ffffffff1660e01b81526004016122c693929190615783565b602060405180830381865af41580156122e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230791906157ba565b905092915050565b6060600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e6303c242519091846040518363ffffffff1660e01b815260040161234d9291906157e7565b602060405180830381865af415801561236a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238e9190615846565b8054806020026020016040519081016040528092919081815260200182805480156123d857602002820191906000526020600020905b8154815260200190600101908083116123c4575b50505050509050919050565b6123ec612bda565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612452576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245b81612d35565b50565b6000601560010160006124708461136b565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900460ff169050919050565b601d60010182826040516124d7929190615500565b908152602001604051809103902060040160149054906101000a900460ff161580612527575042601d6001018383604051612513929190615500565b908152602001604051809103902060030154105b1561256b5781816040517f06dac5070000000000000000000000000000000000000000000000000000000081526004016125629291906158a0565b60405180910390fd5b6125b98383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061294b565b6001601d60010183836040516125d0929190615500565b9081526020016040518091039020600201546125ec9190615654565b601d6001018383604051612601929190615500565b908152602001604051809103902060020181905550612665338484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061318f565b505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6126dd816130c1565b61271e57806040517f3d2f7ef60000000000000000000000000000000000000000000000000000000081526004016127159190613fed565b60405180910390fd5b50565b61272a8161245e565b15612761576040517f35857a7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b3373ffffffffffffffffffffffffffffffffffffffff166127848261136b565b73ffffffffffffffffffffffffffffffffffffffff16146127de5733816040517fa52847350000000000000000000000000000000000000000000000000000000081526004016127d59291906158c4565b60405180910390fd5b600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263735b7846909184846040518463ffffffff1660e01b815260040161281c939291906158ed565b60006040518083038186803b15801561283457600080fd5b505af4158015612848573d6000803e3d6000fd5b50505050808273ffffffffffffffffffffffffffffffffffffffff1661286d8361136b565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60277317e46924e6e004c5618bca34feb32c14d55fce5163284800ce90918585856040518563ffffffff1660e01b81526004016128f394939291906151d6565b60006040518083038186803b15801561290b57600080fd5b505af415801561291f573d6000803e3d6000fd5b50505050505050565b6129323382612f27565b61293b81612721565b6129468383836131a7565b505050565b60006129578383611567565b90506000601d6001018360405161296e9190615955565b908152602001604051809103902060040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060006129ae8385611ba5565b90506000811115612a7e578173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156129ff573d6000803e3d6000fd5b507f885e6f6235626292940f78c947a331f4c7c1d7f50a48b38092cf546bc9c7907a601d60010185604051612a349190615955565b908152602001604051809103902060040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682604051612a759291906158c4565b60405180910390a15b602660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc8285612ac6919061596c565b9081150290604051600060405180830381858888f19350505050158015612af1573d6000803e3d6000fd5b506001601d60010185604051612b079190615955565b908152602001604051809103902060020154612b239190615654565b601d60010185604051612b369190615955565b9081526020016040518091039020600201819055505050505050565b612b5c3384612f27565b601d73a1f273011d271ec06d35b7e731e7f899391cd9b063befc0ab6909184846040518463ffffffff1660e01b8152600401612b9a93929190615341565b60006040518083038186803b158015612bb257600080fd5b505af4158015612bc6573d6000803e3d6000fd5b50505050612bd5838383613287565b505050565b3373ffffffffffffffffffffffffffffffffffffffff16612bf96116ea565b73ffffffffffffffffffffffffffffffffffffffff1614612c5157336040517fd4ed9a17000000000000000000000000000000000000000000000000000000008152600401612c489190613d75565b60405180910390fd5b565b600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d12633f4e7cce909183612c7b8561230f565b6040518463ffffffff1660e01b8152600401612c9993929190615a25565b60006040518083038186803b158015612cb157600080fd5b505af4158015612cc5573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612d32576040517f49e27cff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b612e3982826040518060400160405280600181526020017f200000000000000000000000000000000000000000000000000000000000000081525061318f565b5050565b8015612eb457600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263b2875b199091846040518363ffffffff1660e01b8152600401612e7f929190615a63565b60006040518083038186803b158015612e9757600080fd5b505af4158015612eab573d6000803e3d6000fd5b50505050612f23565b600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d12630aeeeecb909184336040518463ffffffff1660e01b8152600401612ef293929190615783565b60006040518083038186803b158015612f0a57600080fd5b505af4158015612f1e573d6000803e3d6000fd5b505050505b5050565b6000612f328261136b565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480612f745750612f738184612286565b5b8061302657508273ffffffffffffffffffffffffffffffffffffffff16600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263dc6cf67e9091856040518363ffffffff1660e01b8152600401612fcd929190615a8c565b602060405180830381865af4158015612fea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300e919061524b565b73ffffffffffffffffffffffffffffffffffffffff16145b6130695782826040517fa52847350000000000000000000000000000000000000000000000000000000081526004016130609291906158c4565b60405180910390fd5b505050565b61307a84848484613368565b6130b0576040517fe0c7635200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130bb8484846131a7565b50505050565b6000600d600601600083815260200190815260200160002060000160149054906101000a900460ff169050919050565b60008060016130fe610fa8565b6131089190615654565b905061311483826134df565b80915050919050565b601d73a1f273011d271ec06d35b7e731e7f899391cd9b063a253d058909184846040518463ffffffff1660e01b815260040161315b9392919061572a565b60006040518083038186803b15801561317357600080fd5b505af4158015613187573d6000803e3d6000fd5b505050505050565b6131a261319b846130f1565b8383613287565b505050565b60006131b2836114fb565b11156131fd576131c1826114fb565b6040517f8b03eb030000000000000000000000000000000000000000000000000000000081526004016131f49190613fed565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613263576040517f9b7cfcb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61326c81613615565b613277838383613684565b6132828383836137d3565b505050565b601d73a1f273011d271ec06d35b7e731e7f899391cd9b063befc0ab6909184846040518463ffffffff1660e01b81526004016132c593929190615341565b60006040518083038186803b1580156132dd57600080fd5b505af41580156132f1573d6000803e3d6000fd5b50505050601d73a1f273011d271ec06d35b7e731e7f899391cd9b063a253d058909185856040518463ffffffff1660e01b81526004016133339392919061572a565b60006040518083038186803b15801561334b57600080fd5b505af415801561335f573d6000803e3d6000fd5b50505050505050565b60006133898473ffffffffffffffffffffffffffffffffffffffff1661388b565b156134d2578373ffffffffffffffffffffffffffffffffffffffff1663150b7a02338786866040518563ffffffff1660e01b81526004016133cd9493929190615b0a565b6020604051808303816000875af192505050801561340957506040513d601f19601f820116820180604052508101906134069190615b6b565b60015b613482573d8060008114613439576040519150601f19603f3d011682016040523d82523d6000602084013e61343e565b606091505b50600081510361347a576040517f9b7cfcb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150506134d7565b600190505b949350505050565b601760009054906101000a900460ff16613525576040517f03eaac9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361359657816040517f17858bbe00000000000000000000000000000000000000000000000000000000815260040161358d9190613d75565b60405180910390fd5b61359f816130c1565b156135e157806040517f8b474e540000000000000000000000000000000000000000000000000000000081526004016135d89190613fed565b60405180910390fd5b6001601860008282546135f49190615654565b9250508190555061360582826138ae565b613611600083836137d3565b5050565b600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263ad8e62069091836040518363ffffffff1660e01b8152600401613651929190615a8c565b60006040518083038186803b15801561366957600080fd5b505af415801561367d573d6000803e3d6000fd5b5050505050565b600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e63a0576ba2909185846040518463ffffffff1660e01b81526004016136c293929190615b98565b60006040518083038186803b1580156136da57600080fd5b505af41580156136ee573d6000803e3d6000fd5b50505050600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e63a0576ba2909185846040518463ffffffff1660e01b815260040161373093929190615b98565b60006040518083038186803b15801561374857600080fd5b505af415801561375c573d6000803e3d6000fd5b50505050600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e63c213e42f909184846040518463ffffffff1660e01b815260040161379e93929190615b98565b60006040518083038186803b1580156137b657600080fd5b505af41580156137ca573d6000803e3d6000fd5b50505050505050565b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46060613885836040518060c0016040528060001515815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200184815260200160011515815250613920565b50505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e63c213e42f909184846040518463ffffffff1660e01b81526004016138ec93929190615b98565b60006040518083038186803b15801561390457600080fd5b505af4158015613918573d6000803e3d6000fd5b505050505050565b80601560010160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506060820151816003015560808201518160040190805190602001906139fa929190613aa9565b5060a08201518160050160006101000a81548160ff0219169083151502179055509050505050565b604051806060016040528060608152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000151581525090565b6040518060c0016040528060008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000151581525090565b828054828255906000526020600020908101928215613b22579160200282015b82811115613b215782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190613ac9565b5b509050613b2f9190613b33565b5090565b5b80821115613b4c576000816000905550600101613b34565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613b9981613b64565b8114613ba457600080fd5b50565b600081359050613bb681613b90565b92915050565b600060208284031215613bd257613bd1613b5a565b5b6000613be084828501613ba7565b91505092915050565b60008115159050919050565b613bfe81613be9565b82525050565b6000602082019050613c196000830184613bf5565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613c59578082015181840152602081019050613c3e565b60008484015250505050565b6000601f19601f8301169050919050565b6000613c8182613c1f565b613c8b8185613c2a565b9350613c9b818560208601613c3b565b613ca481613c65565b840191505092915050565b60006020820190508181036000830152613cc98184613c76565b905092915050565b6000819050919050565b613ce481613cd1565b8114613cef57600080fd5b50565b600081359050613d0181613cdb565b92915050565b600060208284031215613d1d57613d1c613b5a565b5b6000613d2b84828501613cf2565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613d5f82613d34565b9050919050565b613d6f81613d54565b82525050565b6000602082019050613d8a6000830184613d66565b92915050565b613d9981613d54565b8114613da457600080fd5b50565b600081359050613db681613d90565b92915050565b60008060408385031215613dd357613dd2613b5a565b5b6000613de185828601613da7565b9250506020613df285828601613cf2565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613e3e82613c65565b810181811067ffffffffffffffff82111715613e5d57613e5c613e06565b5b80604052505050565b6000613e70613b50565b9050613e7c8282613e35565b919050565b600067ffffffffffffffff821115613e9c57613e9b613e06565b5b613ea582613c65565b9050602081019050919050565b82818337600083830152505050565b6000613ed4613ecf84613e81565b613e66565b905082815260208101848484011115613ef057613eef613e01565b5b613efb848285613eb2565b509392505050565b600082601f830112613f1857613f17613dfc565b5b8135613f28848260208601613ec1565b91505092915050565b60008060008060808587031215613f4b57613f4a613b5a565b5b6000613f5987828801613da7565b9450506020613f6a87828801613da7565b9350506040613f7b87828801613cf2565b925050606085013567ffffffffffffffff811115613f9c57613f9b613b5f565b5b613fa887828801613f03565b91505092959194509250565b613fbd81613b64565b82525050565b6000602082019050613fd86000830184613fb4565b92915050565b613fe781613cd1565b82525050565b60006020820190506140026000830184613fde565b92915050565b60008060006060848603121561402157614020613b5a565b5b600061402f86828701613da7565b935050602061404086828701613da7565b925050604061405186828701613cf2565b9150509250925092565b60006020828403121561407157614070613b5a565b5b600061407f84828501613da7565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6140bd81613d54565b82525050565b600082825260208201905092915050565b60006140df82613c1f565b6140e981856140c3565b93506140f9818560208601613c3b565b61410281613c65565b840191505092915050565b61411681613cd1565b82525050565b61412581613be9565b82525050565b600060e08301600083015161414360008601826140b4565b506020830151848203602086015261415b82826140d4565b9150506040830151848203604086015261417582826140d4565b915050606083015161418a606086018261410d565b50608083015161419d608086018261411c565b5060a08301516141b060a086018261411c565b5060c08301516141c360c086018261411c565b508091505092915050565b60006141da838361412b565b905092915050565b6000602082019050919050565b60006141fa82614088565b6142048185614093565b935083602082028501614216856140a4565b8060005b85811015614252578484038952815161423385826141ce565b945061423e836141e2565b925060208a0199505060018101905061421a565b50829750879550505050505092915050565b6000602082019050818103600083015261427e81846141ef565b905092915050565b600080fd5b600080fd5b60008083601f8401126142a6576142a5613dfc565b5b8235905067ffffffffffffffff8111156142c3576142c2614286565b5b6020830191508360018202830111156142df576142de61428b565b5b9250929050565b600080602083850312156142fd576142fc613b5a565b5b600083013567ffffffffffffffff81111561431b5761431a613b5f565b5b61432785828601614290565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600061436b83836140b4565b60208301905092915050565b6000602082019050919050565b600061438f82614333565b614399818561433e565b93506143a48361434f565b8060005b838110156143d55781516143bc888261435f565b97506143c783614377565b9250506001810190506143a8565b5085935050505092915050565b600060608301600083015184820360008601526143ff8282614384565b915050602083015161441460208601826140b4565b506040830151614427604086018261411c565b508091505092915050565b6000602082019050818103600083015261444c81846143e2565b905092915050565b600067ffffffffffffffff82111561446f5761446e613e06565b5b61447882613c65565b9050602081019050919050565b600061449861449384614454565b613e66565b9050828152602081018484840111156144b4576144b3613e01565b5b6144bf848285613eb2565b509392505050565b600082601f8301126144dc576144db613dfc565b5b81356144ec848260208601614485565b91505092915050565b60008060006060848603121561450e5761450d613b5a565b5b600061451c86828701613cf2565b935050602061452d86828701613cf2565b925050604084013567ffffffffffffffff81111561454e5761454d613b5f565b5b61455a868287016144c7565b9150509250925092565b61456d81613be9565b811461457857600080fd5b50565b60008135905061458a81614564565b92915050565b6000602082840312156145a6576145a5613b5a565b5b60006145b48482850161457b565b91505092915050565b60008060008060008060008060c0898b0312156145dd576145dc613b5a565b5b60006145eb8b828c01613da7565b985050602089013567ffffffffffffffff81111561460c5761460b613b5f565b5b6146188b828c01614290565b9750975050604089013567ffffffffffffffff81111561463b5761463a613b5f565b5b6146478b828c01614290565b9550955050606061465a8b828c01613cf2565b935050608061466b8b828c0161457b565b92505060a061467c8b828c0161457b565b9150509295985092959890939650565b600080604083850312156146a3576146a2613b5a565b5b60006146b185828601613cf2565b925050602083013567ffffffffffffffff8111156146d2576146d1613b5f565b5b6146de858286016144c7565b9150509250929050565b60008083601f8401126146fe576146fd613dfc565b5b8235905067ffffffffffffffff81111561471b5761471a614286565b5b6020830191508360208202830111156147375761473661428b565b5b9250929050565b60008060006040848603121561475757614756613b5a565b5b600061476586828701613da7565b935050602084013567ffffffffffffffff81111561478657614785613b5f565b5b614792868287016146e8565b92509250509250925092565b600080604083850312156147b5576147b4613b5a565b5b60006147c385828601613cf2565b92505060206147d485828601613da7565b9150509250929050565b600080604083850312156147f5576147f4613b5a565b5b600061480385828601613da7565b925050602061481485828601613da7565b9150509250929050565b6000806040838503121561483557614834613b5a565b5b600061484385828601613da7565b92505060206148548582860161457b565b9150509250929050565b60c082016000820151614874600085018261410d565b506020820151614887602085018261410d565b50604082015161489a604085018261410d565b5060608201516148ad606085018261410d565b5060808201516148c060808501826140b4565b5060a08201516148d360a085018261411c565b50505050565b600060c0820190506148ee600083018461485e565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600061492c838361410d565b60208301905092915050565b6000602082019050919050565b6000614950826148f4565b61495a81856148ff565b935061496583614910565b8060005b8381101561499657815161497d8882614920565b975061498883614938565b925050600181019050614969565b5085935050505092915050565b600060208201905081810360008301526149bd8184614945565b905092915050565b600080604083850312156149dc576149db613b5a565b5b60006149ea85828601613cf2565b92505060206149fb85828601613cf2565b9150509250929050565b600080600080600060808688031215614a2157614a20613b5a565b5b600086013567ffffffffffffffff811115614a3f57614a3e613b5f565b5b614a4b88828901614290565b95509550506020614a5e88828901613cf2565b9350506040614a6f88828901613cf2565b9250506060614a8088828901613da7565b9150509295509295909350565b600060208284031215614aa357614aa2613b5a565b5b600082013567ffffffffffffffff811115614ac157614ac0613b5f565b5b614acd848285016144c7565b91505092915050565b60008060408385031215614aed57614aec613b5a565b5b600083013567ffffffffffffffff811115614b0b57614b0a613b5f565b5b614b17858286016144c7565b9250506020614b2885828601613cf2565b9150509250929050565b600080600060408486031215614b4b57614b4a613b5a565b5b6000614b5986828701613cf2565b935050602084013567ffffffffffffffff811115614b7a57614b79613b5f565b5b614b8686828701614290565b92509250509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614bd957607f821691505b602082108103614bec57614beb614b92565b5b50919050565b8082525050565b614c0281613cd1565b82525050565b6000604082019050614c1d6000830185614bf2565b614c2a6020830184614bf9565b9392505050565b600081519050614c4081613cdb565b92915050565b600060208284031215614c5c57614c5b613b5a565b5b6000614c6a84828501614c31565b91505092915050565b8082525050565b614c8381613d54565b82525050565b6000606082019050614c9e6000830186614c73565b614cab6020830185614c7a565b614cb86040830184614c7a565b949350505050565b8082525050565b6000604082019050614cdc6000830185614cc0565b614ce96020830184614c7a565b9392505050565b600067ffffffffffffffff821115614d0b57614d0a613e06565b5b602082029050602081019050919050565b600080fd5b600080fd5b600081519050614d3581613d90565b92915050565b6000614d4e614d4984614454565b613e66565b905082815260208101848484011115614d6a57614d69613e01565b5b614d75848285613c3b565b509392505050565b600082601f830112614d9257614d91613dfc565b5b8151614da2848260208601614d3b565b91505092915050565b600081519050614dba81614564565b92915050565b600060e08284031215614dd657614dd5614d1c565b5b614de060e0613e66565b90506000614df084828501614d26565b600083015250602082015167ffffffffffffffff811115614e1457614e13614d21565b5b614e2084828501614d7d565b602083015250604082015167ffffffffffffffff811115614e4457614e43614d21565b5b614e5084828501614d7d565b6040830152506060614e6484828501614c31565b6060830152506080614e7884828501614dab565b60808301525060a0614e8c84828501614dab565b60a08301525060c0614ea084828501614dab565b60c08301525092915050565b6000614ebf614eba84614cf0565b613e66565b90508083825260208201905060208402830185811115614ee257614ee161428b565b5b835b81811015614f2957805167ffffffffffffffff811115614f0757614f06613dfc565b5b808601614f148982614dc0565b85526020850194505050602081019050614ee4565b5050509392505050565b600082601f830112614f4857614f47613dfc565b5b8151614f58848260208601614eac565b91505092915050565b600060208284031215614f7757614f76613b5a565b5b600082015167ffffffffffffffff811115614f9557614f94613b5f565b5b614fa184828501614f33565b91505092915050565b600082825260208201905092915050565b6000614fc78385614faa565b9350614fd4838584613eb2565b614fdd83613c65565b840190509392505050565b6000604082019050614ffd6000830186614cc0565b8181036020830152615010818486614fbb565b9050949350505050565b600067ffffffffffffffff82111561503557615034613e06565b5b602082029050602081019050919050565b60006150596150548461501a565b613e66565b9050808382526020820190506020840283018581111561507c5761507b61428b565b5b835b818110156150a557806150918882614d26565b84526020840193505060208101905061507e565b5050509392505050565b600082601f8301126150c4576150c3613dfc565b5b81516150d4848260208601615046565b91505092915050565b6000606082840312156150f3576150f2614d1c565b5b6150fd6060613e66565b9050600082015167ffffffffffffffff81111561511d5761511c614d21565b5b615129848285016150af565b600083015250602061513d84828501614d26565b602083015250604061515184828501614dab565b60408301525092915050565b60006020828403121561517357615172613b5a565b5b600082015167ffffffffffffffff81111561519157615190613b5f565b5b61519d848285016150dd565b91505092915050565b8082525050565b60006040820190506151c260008301856151a6565b6151cf6020830184614c7a565b9392505050565b60006080820190506151eb6000830187614c73565b6151f86020830186614c7a565b6152056040830185614c7a565b6152126060830184614bf9565b95945050505050565b8082525050565b6000604082019050615237600083018561521b565b6152446020830184614bf9565b9392505050565b60006020828403121561526157615260613b5a565b5b600061526f84828501614d26565b91505092915050565b61528181613be9565b82525050565b600060e08201905061529c600083018c614cc0565b6152a9602083018b614c7a565b81810360408301526152bc81898b614fbb565b905081810360608301526152d1818789614fbb565b90506152e06080830186614bf9565b6152ed60a0830185615278565b6152fa60c0830184615278565b9a9950505050505050505050565b600061531382613c1f565b61531d8185614faa565b935061532d818560208601613c3b565b61533681613c65565b840191505092915050565b60006060820190506153566000830186614bf2565b6153636020830185614bf9565b81810360408301526153758184615308565b9050949350505050565b600082825260208201905092915050565b600080fd5b82818337505050565b60006153aa838561537f565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156153dd576153dc615390565b5b6020830292506153ee838584615395565b82840190509392505050565b600060608201905061540f6000830187614c73565b61541c6020830186614c7a565b818103604083015261542f81848661539e565b905095945050505050565b600060608201905061544f60008301866151a6565b61545c6020830185614c7a565b6154696040830184614c7a565b949350505050565b8082525050565b600060408201905061548d6000830185615471565b61549a6020830184615278565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b60006154e783856154d0565b93506154f4838584613eb2565b82840190509392505050565b600061550d8284866154db565b91508190509392505050565b600067ffffffffffffffff82111561553457615533613e06565b5b602082029050602081019050919050565b600061555861555384615519565b613e66565b9050808382526020820190506020840283018581111561557b5761557a61428b565b5b835b818110156155a457806155908882614c31565b84526020840193505060208101905061557d565b5050509392505050565b600082601f8301126155c3576155c2613dfc565b5b81516155d3848260208601615545565b91505092915050565b6000602082840312156155f2576155f1613b5a565b5b600082015167ffffffffffffffff8111156156105761560f613b5f565b5b61561c848285016155ae565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061565f82613cd1565b915061566a83613cd1565b925082820190508082111561568257615681615625565b5b92915050565b600060408201905061569d6000830185615471565b6156aa6020830184614bf9565b9392505050565b6000602082840312156156c7576156c6613b5a565b5b600082015167ffffffffffffffff8111156156e5576156e4613b5f565b5b6156f184828501614d7d565b91505092915050565b600060408201905061570f6000830185615471565b81810360208301526157218184615308565b90509392505050565b600060608201905061573f6000830186614bf2565b61574c6020830185614bf9565b6157596040830184614bf9565b949350505050565b60006020820190506157766000830184615471565b92915050565b8082525050565b6000606082019050615798600083018661577c565b6157a56020830185614c7a565b6157b26040830184614c7a565b949350505050565b6000602082840312156157d0576157cf613b5a565b5b60006157de84828501614dab565b91505092915050565b60006040820190506157fc600083018561521b565b6158096020830184614c7a565b9392505050565b6000819050919050565b61582381615810565b811461582e57600080fd5b50565b6000815190506158408161581a565b92915050565b60006020828403121561585c5761585b613b5a565b5b600061586a84828501615831565b91505092915050565b600061587f8385613c2a565b935061588c838584613eb2565b61589583613c65565b840190509392505050565b600060208201905081810360008301526158bb818486615873565b90509392505050565b60006040820190506158d96000830185613d66565b6158e66020830184613fde565b9392505050565b6000606082019050615902600083018661577c565b61590f6020830185614c7a565b61591c6040830184614bf9565b949350505050565b600061592f82613c1f565b61593981856154d0565b9350615949818560208601613c3b565b80840191505092915050565b60006159618284615924565b915081905092915050565b600061597782613cd1565b915061598283613cd1565b925082820390508181111561599a57615999615625565b5b92915050565b6159a981613cd1565b82525050565b60006159bb83836159a0565b60208301905092915050565b60006159d2826148f4565b6159dc818561537f565b93506159e783614910565b8060005b83811015615a185781516159ff88826159af565b9750615a0a83614938565b9250506001810190506159eb565b5085935050505092915050565b6000606082019050615a3a600083018661577c565b615a476020830185614c7a565b8181036040830152615a5981846159c7565b9050949350505050565b6000604082019050615a78600083018561577c565b615a856020830184614c7a565b9392505050565b6000604082019050615aa1600083018561577c565b615aae6020830184614bf9565b9392505050565b600081519050919050565b600082825260208201905092915050565b6000615adc82615ab5565b615ae68185615ac0565b9350615af6818560208601613c3b565b615aff81613c65565b840191505092915050565b6000608082019050615b1f6000830187613d66565b615b2c6020830186613d66565b615b396040830185613fde565b8181036060830152615b4b8184615ad1565b905095945050505050565b600081519050615b6581613b90565b92915050565b600060208284031215615b8157615b80613b5a565b5b6000615b8f84828501615b56565b91505092915050565b6000606082019050615bad600083018661521b565b615bba6020830185614c7a565b615bc76040830184614bf9565b94935050505056fea26469706673582212200eb08c26c3542c5c9c4560e462876f5bb2f5cbe65e44c3ea9da70e6ba208291964736f6c634300081100330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000104f534d20537562736372697074696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034f534d0000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x60806040526004361061031a5760003560e01c8063937506f8116101ab578063c87b56dd116100f7578063de3efc9111610095578063ea66aeb31161006f578063ea66aeb314610c6d578063f2fde38b14610caa578063f6aacfb114610cd3578063fbd6a8af14610d105761031a565b8063de3efc9114610bc8578063e8a3d48514610c05578063e985e9c514610c305761031a565b8063cde317af116100d1578063cde317af14610b10578063cf41175914610b4d578063d480924d14610b76578063d6cd022e14610b9f5761031a565b8063c87b56dd14610a81578063cc2e3ee114610abe578063ccb4807b14610ae75761031a565b8063a2cd995d11610164578063af6f26cd1161013e578063af6f26cd146109b5578063b88d4fde146109f2578063ba4b62bf14610a1b578063bebd74ad14610a585761031a565b8063a2cd995d1461091f578063a9c133c71461095c578063ae38b5cf146109995761031a565b8063937506f81461080c578063940cd05b1461084957806395d89b4114610872578063a0712d681461089d578063a1a39af2146108b9578063a22cb465146108f65761031a565b806342842e0e1161026a57806370a08231116102235780638293744b116101fd5780638293744b1461075257806389cea3dd1461077b5780638da5cb5b146107b8578063911c9874146107e35761031a565b806370a08231146106c1578063715018a6146106fe57806380b9b855146107155761031a565b806342842e0e146105a357806353ca912a146105cc5780636264cc4e146105f55780636352211e146106325780636500d4111461066f5780636afc1334146106985761031a565b806318160ddd116102d75780632de409f3116102b15780632de409f3146104f857806335ca1c79146105355780633912928a1461055e5780633bbed4a01461057a5761031a565b806318160ddd1461046757806323b872dd146104925780632b603c71146104bb5761031a565b806301ffc9a71461031f57806306fdde031461035c578063081812fc14610387578063095ea7b3146103c4578063150b7a02146103ed57806317c957091461042a575b600080fd5b34801561032b57600080fd5b5061034660048036038101906103419190613bbc565b610d2c565b6040516103539190613c04565b60405180910390f35b34801561036857600080fd5b50610371610e0e565b60405161037e9190613caf565b60405180910390f35b34801561039357600080fd5b506103ae60048036038101906103a99190613d07565b610ea0565b6040516103bb9190613d75565b60405180910390f35b3480156103d057600080fd5b506103eb60048036038101906103e69190613dbc565b610eec565b005b3480156103f957600080fd5b50610414600480360381019061040f9190613f31565b610f03565b6040516104219190613fc3565b60405180910390f35b34801561043657600080fd5b50610451600480360381019061044c9190613d07565b610f22565b60405161045e9190613fed565b60405180910390f35b34801561047357600080fd5b5061047c610fa8565b6040516104899190613fed565b60405180910390f35b34801561049e57600080fd5b506104b960048036038101906104b49190614008565b610fb2565b005b3480156104c757600080fd5b506104e260048036038101906104dd919061405b565b611030565b6040516104ef9190614264565b60405180910390f35b34801561050457600080fd5b5061051f600480360381019061051a91906142e6565b6110bb565b60405161052c9190614432565b60405180910390f35b34801561054157600080fd5b5061055c60048036038101906105579190613d07565b61114f565b005b610578600480360381019061057391906144f5565b6111c6565b005b34801561058657600080fd5b506105a1600480360381019061059c919061405b565b6111e0565b005b3480156105af57600080fd5b506105ca60048036038101906105c59190614008565b61122c565b005b3480156105d857600080fd5b506105f360048036038101906105ee9190614590565b6112ba565b005b34801561060157600080fd5b5061061c60048036038101906106179190614008565b6112df565b6040516106299190613fed565b60405180910390f35b34801561063e57600080fd5b5061065960048036038101906106549190613d07565b61136b565b6040516106669190613d75565b60405180910390f35b34801561067b57600080fd5b50610696600480360381019061069191906145bd565b6113f1565b005b3480156106a457600080fd5b506106bf60048036038101906106ba9190613d07565b611475565b005b3480156106cd57600080fd5b506106e860048036038101906106e3919061405b565b6114fb565b6040516106f59190613fed565b60405180910390f35b34801561070a57600080fd5b50610713611553565b005b34801561072157600080fd5b5061073c6004803603810190610737919061468c565b611567565b6040516107499190613fed565b60405180910390f35b34801561075e57600080fd5b506107796004803603810190610774919061473e565b6115ef565b005b34801561078757600080fd5b506107a2600480360381019061079d919061405b565b611664565b6040516107af9190613fed565b60405180910390f35b3480156107c457600080fd5b506107cd6116ea565b6040516107da9190613d75565b60405180910390f35b3480156107ef57600080fd5b5061080a6004803603810190610805919061479e565b611713565b005b34801561081857600080fd5b50610833600480360381019061082e91906147de565b61178d565b6040516108409190613fed565b60405180910390f35b34801561085557600080fd5b50610870600480360381019061086b9190614590565b611816565b005b34801561087e57600080fd5b5061088761188d565b6040516108949190613caf565b60405180910390f35b6108b760048036038101906108b29190613d07565b61191f565b005b3480156108c557600080fd5b506108e060048036038101906108db9190613d07565b61196b565b6040516108ed9190613fed565b60405180910390f35b34801561090257600080fd5b5061091d6004803603810190610918919061481e565b6119c2565b005b34801561092b57600080fd5b50610946600480360381019061094191906142e6565b6119fc565b60405161095391906148d9565b60405180910390f35b34801561096857600080fd5b50610983600480360381019061097e91906147de565b611ad3565b60405161099091906149a3565b60405180910390f35b6109b360048036038101906109ae91906149c5565b611b61565b005b3480156109c157600080fd5b506109dc60048036038101906109d7919061468c565b611ba5565b6040516109e99190613fed565b60405180910390f35b3480156109fe57600080fd5b50610a196004803603810190610a149190613f31565b611c2e565b005b348015610a2757600080fd5b50610a426004803603810190610a3d9190613d07565b611c53565b604051610a4f9190613fed565b60405180910390f35b348015610a6457600080fd5b50610a7f6004803603810190610a7a9190614a05565b611cd9565b005b348015610a8d57600080fd5b50610aa86004803603810190610aa39190613d07565b611df2565b604051610ab59190613caf565b60405180910390f35b348015610aca57600080fd5b50610ae56004803603810190610ae0919061405b565b611e7d565b005b348015610af357600080fd5b50610b0e6004803603810190610b099190614a8d565b611eec565b005b348015610b1c57600080fd5b50610b376004803603810190610b329190613d07565b611f63565b604051610b449190613c04565b60405180910390f35b348015610b5957600080fd5b50610b746004803603810190610b6f9190613dbc565b611f75565b005b348015610b8257600080fd5b50610b9d6004803603810190610b989190614ad6565b611f93565b005b348015610bab57600080fd5b50610bc66004803603810190610bc191906149c5565b6120f7565b005b348015610bd457600080fd5b50610bef6004803603810190610bea9190613d07565b612171565b604051610bfc9190613d75565b60405180910390f35b348015610c1157600080fd5b50610c1a6121ff565b604051610c279190613caf565b60405180910390f35b348015610c3c57600080fd5b50610c576004803603810190610c5291906147de565b612286565b604051610c649190613c04565b60405180910390f35b348015610c7957600080fd5b50610c946004803603810190610c8f919061405b565b61230f565b604051610ca191906149a3565b60405180910390f35b348015610cb657600080fd5b50610cd16004803603810190610ccc919061405b565b6123e4565b005b348015610cdf57600080fd5b50610cfa6004803603810190610cf59190613d07565b61245e565b604051610d079190613c04565b60405180910390f35b610d2a6004803603810190610d259190614b32565b6124c2565b005b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610df757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610e075750610e068261266a565b5b9050919050565b606060078054610e1d90614bc1565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4990614bc1565b8015610e965780601f10610e6b57610100808354040283529160200191610e96565b820191906000526020600020905b815481529060010190602001808311610e7957829003601f168201915b5050505050905090565b6000610eab826126d4565b600d600601600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b610ef581612721565b610eff8282612764565b5050565b6000610f108433856128b3565b63150b7a0260e01b9050949350505050565b6000601d73a1f273011d271ec06d35b7e731e7f899391cd9b06347f5a81c9091846040518363ffffffff1660e01b8152600401610f60929190614c08565b602060405180830381865af4158015610f7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa19190614c46565b9050919050565b6000601854905090565b610fbd838383612928565b60277317e46924e6e004c5618bca34feb32c14d55fce51636e520c42909185856040518463ffffffff1660e01b8152600401610ffb93929190614c89565b60006040518083038186803b15801561101357600080fd5b505af4158015611027573d6000803e3d6000fd5b50505050505050565b60606019732008152272e4678d4661891125a070e4c3e5edc86308ce42cc9091846040518363ffffffff1660e01b815260040161106e929190614cc7565b600060405180830381865af415801561108b573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906110b49190614f61565b9050919050565b6110c3613a22565b6019732008152272e4678d4661891125a070e4c3e5edc863fd16883c909185856040518463ffffffff1660e01b815260040161110193929190614fe8565b600060405180830381865af415801561111e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611147919061515d565b905092915050565b6015731b7b48434d041eede56b532f2542ac3e1df42dba638fb14e3b90916111768461136b565b6040518363ffffffff1660e01b81526004016111939291906151ad565b60006040518083038186803b1580156111ab57600080fd5b505af41580156111bf573d6000803e3d6000fd5b5050505050565b6111d0828261294b565b6111db838383612b52565b505050565b6111e8612bda565b80602660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61124783838360405180602001604052806000815250611c2e565b60277317e46924e6e004c5618bca34feb32c14d55fce51636e520c42909185856040518463ffffffff1660e01b815260040161128593929190614c89565b60006040518083038186803b15801561129d57600080fd5b505af41580156112b1573d6000803e3d6000fd5b50505050505050565b6112c2612bda565b80601760006101000a81548160ff02191690831515021790555050565b600060277317e46924e6e004c5618bca34feb32c14d55fce51635908f8e590918686866040518563ffffffff1660e01b815260040161132194939291906151d6565b602060405180830381865af415801561133e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113629190614c46565b90509392505050565b6000600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e630266c7a39091846040518363ffffffff1660e01b81526004016113a9929190615222565b602060405180830381865af41580156113c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ea919061524b565b9050919050565b6019732008152272e4678d4661891125a070e4c3e5edc8639895d47d90918a8a8a8a8a8a8a8a6040518a63ffffffff1660e01b815260040161143b99989796959493929190615287565b60006040518083038186803b15801561145357600080fd5b505af4158015611467573d6000803e3d6000fd5b505050505050505050505050565b60006114808261136b565b905061148b81612c53565b6015731b7b48434d041eede56b532f2542ac3e1df42dba63b04686629091836040518363ffffffff1660e01b81526004016114c79291906151ad565b60006040518083038186803b1580156114df57600080fd5b505af41580156114f3573d6000803e3d6000fd5b505050505050565b600061150682612ccc565b600960010160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b61155b612bda565b6115656000612d35565b565b6000601d73a1f273011d271ec06d35b7e731e7f899391cd9b0629c1dd4909185856040518463ffffffff1660e01b81526004016115a693929190615341565b602060405180830381865af41580156115c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e79190614c46565b905092915050565b60277317e46924e6e004c5618bca34feb32c14d55fce51634412be0090918585856040518563ffffffff1660e01b815260040161162f94939291906153fa565b60006040518083038186803b15801561164757600080fd5b505af415801561165b573d6000803e3d6000fd5b50505050505050565b60006019732008152272e4678d4661891125a070e4c3e5edc86373632d479091846040518363ffffffff1660e01b81526004016116a2929190614cc7565b602060405180830381865af41580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e39190614c46565b9050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6015731b7b48434d041eede56b532f2542ac3e1df42dba6311841d7090918361173b8661136b565b6040518463ffffffff1660e01b81526004016117599392919061543a565b60006040518083038186803b15801561177157600080fd5b505af4158015611785573d6000803e3d6000fd5b505050505050565b600060277317e46924e6e004c5618bca34feb32c14d55fce5163c412a736909185856040518463ffffffff1660e01b81526004016117cd93929190614c89565b602060405180830381865af41580156117ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180e9190614c46565b905092915050565b61181e612bda565b600173c4a3392eb009a88e9a8b4101587a1a7bcf80432663da1542a69091836040518363ffffffff1660e01b815260040161185a929190615478565b60006040518083038186803b15801561187257600080fd5b505af4158015611886573d6000803e3d6000fd5b5050505050565b60606008805461189c90614bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546118c890614bc1565b80156119155780601f106118ea57610100808354040283529160200191611915565b820191906000526020600020905b8154815290600101906020018083116118f857829003601f168201915b5050505050905090565b61195e816040518060400160405280600181526020017f200000000000000000000000000000000000000000000000000000000000000081525061294b565b6119683382612df9565b50565b60006015600101600061197d8461136b565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101549050919050565b6119ee6119ce3361230f565b6000815181106119e1576119e06154a1565b5b6020026020010151612721565b6119f88282612e3d565b5050565b611a04613a5b565b601d6001018383604051611a19929190615500565b90815260200160405180910390206040518060c0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016004820160149054906101000a900460ff161515151581525050905092915050565b606060277317e46924e6e004c5618bca34feb32c14d55fce5163c680a5c1909185856040518463ffffffff1660e01b8152600401611b1393929190614c89565b600060405180830381865af4158015611b30573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611b5991906155dc565b905092915050565b611ba182826040518060400160405280600181526020017f20000000000000000000000000000000000000000000000000000000000000008152506111c6565b5050565b6000601d73a1f273011d271ec06d35b7e731e7f899391cd9b063967cf8d1909185856040518463ffffffff1660e01b8152600401611be593929190615341565b602060405180830381865af4158015611c02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c269190614c46565b905092915050565b611c383383612f27565b611c4182612721565b611c4d8484848461306e565b50505050565b6000601d73a1f273011d271ec06d35b7e731e7f899391cd9b063db48b3009091846040518363ffffffff1660e01b8152600401611c91929190614c08565b602060405180830381865af4158015611cae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd29190614c46565b9050919050565b611ce1612bda565b6040518060c00160405280848152602001838152602001600081526020016224ea0042611d0e9190615654565b81526020018273ffffffffffffffffffffffffffffffffffffffff16815260200160011515815250601d6001018686604051611d4b929190615500565b90815260200160405180910390206000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160040160146101000a81548160ff0219169083151502179055509050505050505050565b6060600173c4a3392eb009a88e9a8b4101587a1a7bcf80432663d30eae479091846040518363ffffffff1660e01b8152600401611e30929190615688565b600060405180830381865af4158015611e4d573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611e7691906156b1565b9050919050565b6019732008152272e4678d4661891125a070e4c3e5edc863b81093009091836040518363ffffffff1660e01b8152600401611eb9929190614cc7565b60006040518083038186803b158015611ed157600080fd5b505af4158015611ee5573d6000803e3d6000fd5b5050505050565b611ef4612bda565b600173c4a3392eb009a88e9a8b4101587a1a7bcf804326632d5459e29091836040518363ffffffff1660e01b8152600401611f309291906156fa565b60006040518083038186803b158015611f4857600080fd5b505af4158015611f5c573d6000803e3d6000fd5b5050505050565b6000611f6e826130c1565b9050919050565b611f7d612bda565b611f8f611f89836130f1565b8261311d565b5050565b6002810361200c57600173c4a3392eb009a88e9a8b4101587a1a7bcf80432663db6a3cab9091846040518363ffffffff1660e01b8152600401611fd79291906156fa565b60006040518083038186803b158015611fef57600080fd5b505af4158015612003573d6000803e3d6000fd5b505050506120f3565b6003810361208557600173c4a3392eb009a88e9a8b4101587a1a7bcf8043266348b5a5a39091846040518363ffffffff1660e01b81526004016120509291906156fa565b60006040518083038186803b15801561206857600080fd5b505af415801561207c573d6000803e3d6000fd5b505050506120f2565b600173c4a3392eb009a88e9a8b4101587a1a7bcf804326638bebb5869091846040518363ffffffff1660e01b81526004016120c19291906156fa565b60006040518083038186803b1580156120d957600080fd5b505af41580156120ed573d6000803e3d6000fd5b505050505b5b5050565b6120ff612bda565b601d73a1f273011d271ec06d35b7e731e7f899391cd9b0637ca5f858909184846040518463ffffffff1660e01b815260040161213d9392919061572a565b60006040518083038186803b15801561215557600080fd5b505af4158015612169573d6000803e3d6000fd5b505050505050565b60006015731b7b48434d041eede56b532f2542ac3e1df42dba63f1650c05909161219a8561136b565b6040518363ffffffff1660e01b81526004016121b79291906151ad565b602060405180830381865af41580156121d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f8919061524b565b9050919050565b6060600173c4a3392eb009a88e9a8b4101587a1a7bcf804326636ae383de90916040518263ffffffff1660e01b815260040161223b9190615761565b600060405180830381865af4158015612258573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061228191906156b1565b905090565b6000600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263e4e0a723909185856040518463ffffffff1660e01b81526004016122c693929190615783565b602060405180830381865af41580156122e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230791906157ba565b905092915050565b6060600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e6303c242519091846040518363ffffffff1660e01b815260040161234d9291906157e7565b602060405180830381865af415801561236a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238e9190615846565b8054806020026020016040519081016040528092919081815260200182805480156123d857602002820191906000526020600020905b8154815260200190600101908083116123c4575b50505050509050919050565b6123ec612bda565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612452576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245b81612d35565b50565b6000601560010160006124708461136b565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900460ff169050919050565b601d60010182826040516124d7929190615500565b908152602001604051809103902060040160149054906101000a900460ff161580612527575042601d6001018383604051612513929190615500565b908152602001604051809103902060030154105b1561256b5781816040517f06dac5070000000000000000000000000000000000000000000000000000000081526004016125629291906158a0565b60405180910390fd5b6125b98383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061294b565b6001601d60010183836040516125d0929190615500565b9081526020016040518091039020600201546125ec9190615654565b601d6001018383604051612601929190615500565b908152602001604051809103902060020181905550612665338484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061318f565b505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6126dd816130c1565b61271e57806040517f3d2f7ef60000000000000000000000000000000000000000000000000000000081526004016127159190613fed565b60405180910390fd5b50565b61272a8161245e565b15612761576040517f35857a7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b3373ffffffffffffffffffffffffffffffffffffffff166127848261136b565b73ffffffffffffffffffffffffffffffffffffffff16146127de5733816040517fa52847350000000000000000000000000000000000000000000000000000000081526004016127d59291906158c4565b60405180910390fd5b600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263735b7846909184846040518463ffffffff1660e01b815260040161281c939291906158ed565b60006040518083038186803b15801561283457600080fd5b505af4158015612848573d6000803e3d6000fd5b50505050808273ffffffffffffffffffffffffffffffffffffffff1661286d8361136b565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60277317e46924e6e004c5618bca34feb32c14d55fce5163284800ce90918585856040518563ffffffff1660e01b81526004016128f394939291906151d6565b60006040518083038186803b15801561290b57600080fd5b505af415801561291f573d6000803e3d6000fd5b50505050505050565b6129323382612f27565b61293b81612721565b6129468383836131a7565b505050565b60006129578383611567565b90506000601d6001018360405161296e9190615955565b908152602001604051809103902060040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060006129ae8385611ba5565b90506000811115612a7e578173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156129ff573d6000803e3d6000fd5b507f885e6f6235626292940f78c947a331f4c7c1d7f50a48b38092cf546bc9c7907a601d60010185604051612a349190615955565b908152602001604051809103902060040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682604051612a759291906158c4565b60405180910390a15b602660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc8285612ac6919061596c565b9081150290604051600060405180830381858888f19350505050158015612af1573d6000803e3d6000fd5b506001601d60010185604051612b079190615955565b908152602001604051809103902060020154612b239190615654565b601d60010185604051612b369190615955565b9081526020016040518091039020600201819055505050505050565b612b5c3384612f27565b601d73a1f273011d271ec06d35b7e731e7f899391cd9b063befc0ab6909184846040518463ffffffff1660e01b8152600401612b9a93929190615341565b60006040518083038186803b158015612bb257600080fd5b505af4158015612bc6573d6000803e3d6000fd5b50505050612bd5838383613287565b505050565b3373ffffffffffffffffffffffffffffffffffffffff16612bf96116ea565b73ffffffffffffffffffffffffffffffffffffffff1614612c5157336040517fd4ed9a17000000000000000000000000000000000000000000000000000000008152600401612c489190613d75565b60405180910390fd5b565b600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d12633f4e7cce909183612c7b8561230f565b6040518463ffffffff1660e01b8152600401612c9993929190615a25565b60006040518083038186803b158015612cb157600080fd5b505af4158015612cc5573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612d32576040517f49e27cff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b612e3982826040518060400160405280600181526020017f200000000000000000000000000000000000000000000000000000000000000081525061318f565b5050565b8015612eb457600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263b2875b199091846040518363ffffffff1660e01b8152600401612e7f929190615a63565b60006040518083038186803b158015612e9757600080fd5b505af4158015612eab573d6000803e3d6000fd5b50505050612f23565b600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d12630aeeeecb909184336040518463ffffffff1660e01b8152600401612ef293929190615783565b60006040518083038186803b158015612f0a57600080fd5b505af4158015612f1e573d6000803e3d6000fd5b505050505b5050565b6000612f328261136b565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480612f745750612f738184612286565b5b8061302657508273ffffffffffffffffffffffffffffffffffffffff16600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263dc6cf67e9091856040518363ffffffff1660e01b8152600401612fcd929190615a8c565b602060405180830381865af4158015612fea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300e919061524b565b73ffffffffffffffffffffffffffffffffffffffff16145b6130695782826040517fa52847350000000000000000000000000000000000000000000000000000000081526004016130609291906158c4565b60405180910390fd5b505050565b61307a84848484613368565b6130b0576040517fe0c7635200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130bb8484846131a7565b50505050565b6000600d600601600083815260200190815260200160002060000160149054906101000a900460ff169050919050565b60008060016130fe610fa8565b6131089190615654565b905061311483826134df565b80915050919050565b601d73a1f273011d271ec06d35b7e731e7f899391cd9b063a253d058909184846040518463ffffffff1660e01b815260040161315b9392919061572a565b60006040518083038186803b15801561317357600080fd5b505af4158015613187573d6000803e3d6000fd5b505050505050565b6131a261319b846130f1565b8383613287565b505050565b60006131b2836114fb565b11156131fd576131c1826114fb565b6040517f8b03eb030000000000000000000000000000000000000000000000000000000081526004016131f49190613fed565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613263576040517f9b7cfcb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61326c81613615565b613277838383613684565b6132828383836137d3565b505050565b601d73a1f273011d271ec06d35b7e731e7f899391cd9b063befc0ab6909184846040518463ffffffff1660e01b81526004016132c593929190615341565b60006040518083038186803b1580156132dd57600080fd5b505af41580156132f1573d6000803e3d6000fd5b50505050601d73a1f273011d271ec06d35b7e731e7f899391cd9b063a253d058909185856040518463ffffffff1660e01b81526004016133339392919061572a565b60006040518083038186803b15801561334b57600080fd5b505af415801561335f573d6000803e3d6000fd5b50505050505050565b60006133898473ffffffffffffffffffffffffffffffffffffffff1661388b565b156134d2578373ffffffffffffffffffffffffffffffffffffffff1663150b7a02338786866040518563ffffffff1660e01b81526004016133cd9493929190615b0a565b6020604051808303816000875af192505050801561340957506040513d601f19601f820116820180604052508101906134069190615b6b565b60015b613482573d8060008114613439576040519150601f19603f3d011682016040523d82523d6000602084013e61343e565b606091505b50600081510361347a576040517f9b7cfcb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150506134d7565b600190505b949350505050565b601760009054906101000a900460ff16613525576040517f03eaac9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361359657816040517f17858bbe00000000000000000000000000000000000000000000000000000000815260040161358d9190613d75565b60405180910390fd5b61359f816130c1565b156135e157806040517f8b474e540000000000000000000000000000000000000000000000000000000081526004016135d89190613fed565b60405180910390fd5b6001601860008282546135f49190615654565b9250508190555061360582826138ae565b613611600083836137d3565b5050565b600d73d44fc4f2f36e6a75bca189001f2b243dbc7a0d1263ad8e62069091836040518363ffffffff1660e01b8152600401613651929190615a8c565b60006040518083038186803b15801561366957600080fd5b505af415801561367d573d6000803e3d6000fd5b5050505050565b600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e63a0576ba2909185846040518463ffffffff1660e01b81526004016136c293929190615b98565b60006040518083038186803b1580156136da57600080fd5b505af41580156136ee573d6000803e3d6000fd5b50505050600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e63a0576ba2909185846040518463ffffffff1660e01b815260040161373093929190615b98565b60006040518083038186803b15801561374857600080fd5b505af415801561375c573d6000803e3d6000fd5b50505050600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e63c213e42f909184846040518463ffffffff1660e01b815260040161379e93929190615b98565b60006040518083038186803b1580156137b657600080fd5b505af41580156137ca573d6000803e3d6000fd5b50505050505050565b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46060613885836040518060c0016040528060001515815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200184815260200160011515815250613920565b50505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600973f7efe8f7f017b7eba93daab7c7518e6a4f90bf2e63c213e42f909184846040518463ffffffff1660e01b81526004016138ec93929190615b98565b60006040518083038186803b15801561390457600080fd5b505af4158015613918573d6000803e3d6000fd5b505050505050565b80601560010160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506060820151816003015560808201518160040190805190602001906139fa929190613aa9565b5060a08201518160050160006101000a81548160ff0219169083151502179055509050505050565b604051806060016040528060608152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000151581525090565b6040518060c0016040528060008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000151581525090565b828054828255906000526020600020908101928215613b22579160200282015b82811115613b215782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190613ac9565b5b509050613b2f9190613b33565b5090565b5b80821115613b4c576000816000905550600101613b34565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613b9981613b64565b8114613ba457600080fd5b50565b600081359050613bb681613b90565b92915050565b600060208284031215613bd257613bd1613b5a565b5b6000613be084828501613ba7565b91505092915050565b60008115159050919050565b613bfe81613be9565b82525050565b6000602082019050613c196000830184613bf5565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613c59578082015181840152602081019050613c3e565b60008484015250505050565b6000601f19601f8301169050919050565b6000613c8182613c1f565b613c8b8185613c2a565b9350613c9b818560208601613c3b565b613ca481613c65565b840191505092915050565b60006020820190508181036000830152613cc98184613c76565b905092915050565b6000819050919050565b613ce481613cd1565b8114613cef57600080fd5b50565b600081359050613d0181613cdb565b92915050565b600060208284031215613d1d57613d1c613b5a565b5b6000613d2b84828501613cf2565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613d5f82613d34565b9050919050565b613d6f81613d54565b82525050565b6000602082019050613d8a6000830184613d66565b92915050565b613d9981613d54565b8114613da457600080fd5b50565b600081359050613db681613d90565b92915050565b60008060408385031215613dd357613dd2613b5a565b5b6000613de185828601613da7565b9250506020613df285828601613cf2565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613e3e82613c65565b810181811067ffffffffffffffff82111715613e5d57613e5c613e06565b5b80604052505050565b6000613e70613b50565b9050613e7c8282613e35565b919050565b600067ffffffffffffffff821115613e9c57613e9b613e06565b5b613ea582613c65565b9050602081019050919050565b82818337600083830152505050565b6000613ed4613ecf84613e81565b613e66565b905082815260208101848484011115613ef057613eef613e01565b5b613efb848285613eb2565b509392505050565b600082601f830112613f1857613f17613dfc565b5b8135613f28848260208601613ec1565b91505092915050565b60008060008060808587031215613f4b57613f4a613b5a565b5b6000613f5987828801613da7565b9450506020613f6a87828801613da7565b9350506040613f7b87828801613cf2565b925050606085013567ffffffffffffffff811115613f9c57613f9b613b5f565b5b613fa887828801613f03565b91505092959194509250565b613fbd81613b64565b82525050565b6000602082019050613fd86000830184613fb4565b92915050565b613fe781613cd1565b82525050565b60006020820190506140026000830184613fde565b92915050565b60008060006060848603121561402157614020613b5a565b5b600061402f86828701613da7565b935050602061404086828701613da7565b925050604061405186828701613cf2565b9150509250925092565b60006020828403121561407157614070613b5a565b5b600061407f84828501613da7565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6140bd81613d54565b82525050565b600082825260208201905092915050565b60006140df82613c1f565b6140e981856140c3565b93506140f9818560208601613c3b565b61410281613c65565b840191505092915050565b61411681613cd1565b82525050565b61412581613be9565b82525050565b600060e08301600083015161414360008601826140b4565b506020830151848203602086015261415b82826140d4565b9150506040830151848203604086015261417582826140d4565b915050606083015161418a606086018261410d565b50608083015161419d608086018261411c565b5060a08301516141b060a086018261411c565b5060c08301516141c360c086018261411c565b508091505092915050565b60006141da838361412b565b905092915050565b6000602082019050919050565b60006141fa82614088565b6142048185614093565b935083602082028501614216856140a4565b8060005b85811015614252578484038952815161423385826141ce565b945061423e836141e2565b925060208a0199505060018101905061421a565b50829750879550505050505092915050565b6000602082019050818103600083015261427e81846141ef565b905092915050565b600080fd5b600080fd5b60008083601f8401126142a6576142a5613dfc565b5b8235905067ffffffffffffffff8111156142c3576142c2614286565b5b6020830191508360018202830111156142df576142de61428b565b5b9250929050565b600080602083850312156142fd576142fc613b5a565b5b600083013567ffffffffffffffff81111561431b5761431a613b5f565b5b61432785828601614290565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600061436b83836140b4565b60208301905092915050565b6000602082019050919050565b600061438f82614333565b614399818561433e565b93506143a48361434f565b8060005b838110156143d55781516143bc888261435f565b97506143c783614377565b9250506001810190506143a8565b5085935050505092915050565b600060608301600083015184820360008601526143ff8282614384565b915050602083015161441460208601826140b4565b506040830151614427604086018261411c565b508091505092915050565b6000602082019050818103600083015261444c81846143e2565b905092915050565b600067ffffffffffffffff82111561446f5761446e613e06565b5b61447882613c65565b9050602081019050919050565b600061449861449384614454565b613e66565b9050828152602081018484840111156144b4576144b3613e01565b5b6144bf848285613eb2565b509392505050565b600082601f8301126144dc576144db613dfc565b5b81356144ec848260208601614485565b91505092915050565b60008060006060848603121561450e5761450d613b5a565b5b600061451c86828701613cf2565b935050602061452d86828701613cf2565b925050604084013567ffffffffffffffff81111561454e5761454d613b5f565b5b61455a868287016144c7565b9150509250925092565b61456d81613be9565b811461457857600080fd5b50565b60008135905061458a81614564565b92915050565b6000602082840312156145a6576145a5613b5a565b5b60006145b48482850161457b565b91505092915050565b60008060008060008060008060c0898b0312156145dd576145dc613b5a565b5b60006145eb8b828c01613da7565b985050602089013567ffffffffffffffff81111561460c5761460b613b5f565b5b6146188b828c01614290565b9750975050604089013567ffffffffffffffff81111561463b5761463a613b5f565b5b6146478b828c01614290565b9550955050606061465a8b828c01613cf2565b935050608061466b8b828c0161457b565b92505060a061467c8b828c0161457b565b9150509295985092959890939650565b600080604083850312156146a3576146a2613b5a565b5b60006146b185828601613cf2565b925050602083013567ffffffffffffffff8111156146d2576146d1613b5f565b5b6146de858286016144c7565b9150509250929050565b60008083601f8401126146fe576146fd613dfc565b5b8235905067ffffffffffffffff81111561471b5761471a614286565b5b6020830191508360208202830111156147375761473661428b565b5b9250929050565b60008060006040848603121561475757614756613b5a565b5b600061476586828701613da7565b935050602084013567ffffffffffffffff81111561478657614785613b5f565b5b614792868287016146e8565b92509250509250925092565b600080604083850312156147b5576147b4613b5a565b5b60006147c385828601613cf2565b92505060206147d485828601613da7565b9150509250929050565b600080604083850312156147f5576147f4613b5a565b5b600061480385828601613da7565b925050602061481485828601613da7565b9150509250929050565b6000806040838503121561483557614834613b5a565b5b600061484385828601613da7565b92505060206148548582860161457b565b9150509250929050565b60c082016000820151614874600085018261410d565b506020820151614887602085018261410d565b50604082015161489a604085018261410d565b5060608201516148ad606085018261410d565b5060808201516148c060808501826140b4565b5060a08201516148d360a085018261411c565b50505050565b600060c0820190506148ee600083018461485e565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600061492c838361410d565b60208301905092915050565b6000602082019050919050565b6000614950826148f4565b61495a81856148ff565b935061496583614910565b8060005b8381101561499657815161497d8882614920565b975061498883614938565b925050600181019050614969565b5085935050505092915050565b600060208201905081810360008301526149bd8184614945565b905092915050565b600080604083850312156149dc576149db613b5a565b5b60006149ea85828601613cf2565b92505060206149fb85828601613cf2565b9150509250929050565b600080600080600060808688031215614a2157614a20613b5a565b5b600086013567ffffffffffffffff811115614a3f57614a3e613b5f565b5b614a4b88828901614290565b95509550506020614a5e88828901613cf2565b9350506040614a6f88828901613cf2565b9250506060614a8088828901613da7565b9150509295509295909350565b600060208284031215614aa357614aa2613b5a565b5b600082013567ffffffffffffffff811115614ac157614ac0613b5f565b5b614acd848285016144c7565b91505092915050565b60008060408385031215614aed57614aec613b5a565b5b600083013567ffffffffffffffff811115614b0b57614b0a613b5f565b5b614b17858286016144c7565b9250506020614b2885828601613cf2565b9150509250929050565b600080600060408486031215614b4b57614b4a613b5a565b5b6000614b5986828701613cf2565b935050602084013567ffffffffffffffff811115614b7a57614b79613b5f565b5b614b8686828701614290565b92509250509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614bd957607f821691505b602082108103614bec57614beb614b92565b5b50919050565b8082525050565b614c0281613cd1565b82525050565b6000604082019050614c1d6000830185614bf2565b614c2a6020830184614bf9565b9392505050565b600081519050614c4081613cdb565b92915050565b600060208284031215614c5c57614c5b613b5a565b5b6000614c6a84828501614c31565b91505092915050565b8082525050565b614c8381613d54565b82525050565b6000606082019050614c9e6000830186614c73565b614cab6020830185614c7a565b614cb86040830184614c7a565b949350505050565b8082525050565b6000604082019050614cdc6000830185614cc0565b614ce96020830184614c7a565b9392505050565b600067ffffffffffffffff821115614d0b57614d0a613e06565b5b602082029050602081019050919050565b600080fd5b600080fd5b600081519050614d3581613d90565b92915050565b6000614d4e614d4984614454565b613e66565b905082815260208101848484011115614d6a57614d69613e01565b5b614d75848285613c3b565b509392505050565b600082601f830112614d9257614d91613dfc565b5b8151614da2848260208601614d3b565b91505092915050565b600081519050614dba81614564565b92915050565b600060e08284031215614dd657614dd5614d1c565b5b614de060e0613e66565b90506000614df084828501614d26565b600083015250602082015167ffffffffffffffff811115614e1457614e13614d21565b5b614e2084828501614d7d565b602083015250604082015167ffffffffffffffff811115614e4457614e43614d21565b5b614e5084828501614d7d565b6040830152506060614e6484828501614c31565b6060830152506080614e7884828501614dab565b60808301525060a0614e8c84828501614dab565b60a08301525060c0614ea084828501614dab565b60c08301525092915050565b6000614ebf614eba84614cf0565b613e66565b90508083825260208201905060208402830185811115614ee257614ee161428b565b5b835b81811015614f2957805167ffffffffffffffff811115614f0757614f06613dfc565b5b808601614f148982614dc0565b85526020850194505050602081019050614ee4565b5050509392505050565b600082601f830112614f4857614f47613dfc565b5b8151614f58848260208601614eac565b91505092915050565b600060208284031215614f7757614f76613b5a565b5b600082015167ffffffffffffffff811115614f9557614f94613b5f565b5b614fa184828501614f33565b91505092915050565b600082825260208201905092915050565b6000614fc78385614faa565b9350614fd4838584613eb2565b614fdd83613c65565b840190509392505050565b6000604082019050614ffd6000830186614cc0565b8181036020830152615010818486614fbb565b9050949350505050565b600067ffffffffffffffff82111561503557615034613e06565b5b602082029050602081019050919050565b60006150596150548461501a565b613e66565b9050808382526020820190506020840283018581111561507c5761507b61428b565b5b835b818110156150a557806150918882614d26565b84526020840193505060208101905061507e565b5050509392505050565b600082601f8301126150c4576150c3613dfc565b5b81516150d4848260208601615046565b91505092915050565b6000606082840312156150f3576150f2614d1c565b5b6150fd6060613e66565b9050600082015167ffffffffffffffff81111561511d5761511c614d21565b5b615129848285016150af565b600083015250602061513d84828501614d26565b602083015250604061515184828501614dab565b60408301525092915050565b60006020828403121561517357615172613b5a565b5b600082015167ffffffffffffffff81111561519157615190613b5f565b5b61519d848285016150dd565b91505092915050565b8082525050565b60006040820190506151c260008301856151a6565b6151cf6020830184614c7a565b9392505050565b60006080820190506151eb6000830187614c73565b6151f86020830186614c7a565b6152056040830185614c7a565b6152126060830184614bf9565b95945050505050565b8082525050565b6000604082019050615237600083018561521b565b6152446020830184614bf9565b9392505050565b60006020828403121561526157615260613b5a565b5b600061526f84828501614d26565b91505092915050565b61528181613be9565b82525050565b600060e08201905061529c600083018c614cc0565b6152a9602083018b614c7a565b81810360408301526152bc81898b614fbb565b905081810360608301526152d1818789614fbb565b90506152e06080830186614bf9565b6152ed60a0830185615278565b6152fa60c0830184615278565b9a9950505050505050505050565b600061531382613c1f565b61531d8185614faa565b935061532d818560208601613c3b565b61533681613c65565b840191505092915050565b60006060820190506153566000830186614bf2565b6153636020830185614bf9565b81810360408301526153758184615308565b9050949350505050565b600082825260208201905092915050565b600080fd5b82818337505050565b60006153aa838561537f565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156153dd576153dc615390565b5b6020830292506153ee838584615395565b82840190509392505050565b600060608201905061540f6000830187614c73565b61541c6020830186614c7a565b818103604083015261542f81848661539e565b905095945050505050565b600060608201905061544f60008301866151a6565b61545c6020830185614c7a565b6154696040830184614c7a565b949350505050565b8082525050565b600060408201905061548d6000830185615471565b61549a6020830184615278565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b60006154e783856154d0565b93506154f4838584613eb2565b82840190509392505050565b600061550d8284866154db565b91508190509392505050565b600067ffffffffffffffff82111561553457615533613e06565b5b602082029050602081019050919050565b600061555861555384615519565b613e66565b9050808382526020820190506020840283018581111561557b5761557a61428b565b5b835b818110156155a457806155908882614c31565b84526020840193505060208101905061557d565b5050509392505050565b600082601f8301126155c3576155c2613dfc565b5b81516155d3848260208601615545565b91505092915050565b6000602082840312156155f2576155f1613b5a565b5b600082015167ffffffffffffffff8111156156105761560f613b5f565b5b61561c848285016155ae565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061565f82613cd1565b915061566a83613cd1565b925082820190508082111561568257615681615625565b5b92915050565b600060408201905061569d6000830185615471565b6156aa6020830184614bf9565b9392505050565b6000602082840312156156c7576156c6613b5a565b5b600082015167ffffffffffffffff8111156156e5576156e4613b5f565b5b6156f184828501614d7d565b91505092915050565b600060408201905061570f6000830185615471565b81810360208301526157218184615308565b90509392505050565b600060608201905061573f6000830186614bf2565b61574c6020830185614bf9565b6157596040830184614bf9565b949350505050565b60006020820190506157766000830184615471565b92915050565b8082525050565b6000606082019050615798600083018661577c565b6157a56020830185614c7a565b6157b26040830184614c7a565b949350505050565b6000602082840312156157d0576157cf613b5a565b5b60006157de84828501614dab565b91505092915050565b60006040820190506157fc600083018561521b565b6158096020830184614c7a565b9392505050565b6000819050919050565b61582381615810565b811461582e57600080fd5b50565b6000815190506158408161581a565b92915050565b60006020828403121561585c5761585b613b5a565b5b600061586a84828501615831565b91505092915050565b600061587f8385613c2a565b935061588c838584613eb2565b61589583613c65565b840190509392505050565b600060208201905081810360008301526158bb818486615873565b90509392505050565b60006040820190506158d96000830185613d66565b6158e66020830184613fde565b9392505050565b6000606082019050615902600083018661577c565b61590f6020830185614c7a565b61591c6040830184614bf9565b949350505050565b600061592f82613c1f565b61593981856154d0565b9350615949818560208601613c3b565b80840191505092915050565b60006159618284615924565b915081905092915050565b600061597782613cd1565b915061598283613cd1565b925082820390508181111561599a57615999615625565b5b92915050565b6159a981613cd1565b82525050565b60006159bb83836159a0565b60208301905092915050565b60006159d2826148f4565b6159dc818561537f565b93506159e783614910565b8060005b83811015615a185781516159ff88826159af565b9750615a0a83614938565b9250506001810190506159eb565b5085935050505092915050565b6000606082019050615a3a600083018661577c565b615a476020830185614c7a565b8181036040830152615a5981846159c7565b9050949350505050565b6000604082019050615a78600083018561577c565b615a856020830184614c7a565b9392505050565b6000604082019050615aa1600083018561577c565b615aae6020830184614bf9565b9392505050565b600081519050919050565b600082825260208201905092915050565b6000615adc82615ab5565b615ae68185615ac0565b9350615af6818560208601613c3b565b615aff81613c65565b840191505092915050565b6000608082019050615b1f6000830187613d66565b615b2c6020830186613d66565b615b396040830185613fde565b8181036060830152615b4b8184615ad1565b905095945050505050565b600081519050615b6581613b90565b92915050565b600060208284031215615b8157615b80613b5a565b5b6000615b8f84828501615b56565b91505092915050565b6000606082019050615bad600083018661521b565b615bba6020830185614c7a565b615bc76040830184614bf9565b94935050505056fea26469706673582212200eb08c26c3542c5c9c4560e462876f5bb2f5cbe65e44c3ea9da70e6ba208291964736f6c63430008110033

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

0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000104f534d20537562736372697074696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034f534d0000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : name (string): OSM Subscription
Arg [1] : symbol (string): OSM

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [3] : 4f534d20537562736372697074696f6e00000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [5] : 4f534d0000000000000000000000000000000000000000000000000000000000


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.