ETH Price: $2,071.07 (-3.62%)

Contract

0xAFEDA1c4fBEfB8dA87CA7E9D927Bdbc08007B97A
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

TokenTracker

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw164632512023-01-22 15:30:471159 days ago1674401447IN
0xAFEDA1c4...08007B97A
0 ETH0.0017414420.48397631
Withdraw163690212023-01-09 11:43:231172 days ago1673264603IN
0xAFEDA1c4...08007B97A
0 ETH0.0010324114.47091773
Withdraw163690182023-01-09 11:42:471172 days ago1673264567IN
0xAFEDA1c4...08007B97A
0 ETH0.001261716.66075861
Mint For Recipie...163625862023-01-08 14:12:111173 days ago1673187131IN
0xAFEDA1c4...08007B97A
0 ETH0.0023052915.06415979
Safe Transfer Fr...163625602023-01-08 14:06:591173 days ago1673186819IN
0xAFEDA1c4...08007B97A
0 ETH0.0048502515.70291527
Withdraw163624792023-01-08 13:50:471173 days ago1673185847IN
0xAFEDA1c4...08007B97A
0 ETH0.0012813414.26805525
Withdraw163571892023-01-07 20:06:591174 days ago1673122019IN
0xAFEDA1c4...08007B97A
0 ETH0.003018135.49715302
Revoke Contract163514412023-01-07 0:51:471175 days ago1673052707IN
0xAFEDA1c4...08007B97A
0 ETH0.0009881214.9829935
Revoke Contract163513182023-01-07 0:27:111175 days ago1673051231IN
0xAFEDA1c4...08007B97A
0 ETH0.001718517.45434926
Allow Contract163513132023-01-07 0:26:111175 days ago1673051171IN
0xAFEDA1c4...08007B97A
0 ETH0.0032726515.09653882
Allow Contract163513062023-01-07 0:24:471175 days ago1673051087IN
0xAFEDA1c4...08007B97A
0 ETH0.0045569117.45247909
Revoke Contract163510722023-01-06 23:37:351175 days ago1673048255IN
0xAFEDA1c4...08007B97A
0 ETH0.0010358618.03885253
Allow Contract163507022023-01-06 22:23:111175 days ago1673043791IN
0xAFEDA1c4...08007B97A
0 ETH0.0053795120.59540161
Revoke Contract163506932023-01-06 22:21:231175 days ago1673043683IN
0xAFEDA1c4...08007B97A
0 ETH0.0014595222.13081424
Revoke Contract163506872023-01-06 22:20:111175 days ago1673043611IN
0xAFEDA1c4...08007B97A
0 ETH0.0014869823.09813758
Allow Contract163473332023-01-06 11:05:591175 days ago1673003159IN
0xAFEDA1c4...08007B97A
0 ETH0.0044495215.75285894
Revoke Contract163472242023-01-06 10:44:111175 days ago1673001851IN
0xAFEDA1c4...08007B97A
0 ETH0.0015375415.61644697
Allow Contract163472222023-01-06 10:43:471175 days ago1673001827IN
0xAFEDA1c4...08007B97A
0 ETH0.0030366915.64356939
Allow Contract163471542023-01-06 10:29:471175 days ago1673000987IN
0xAFEDA1c4...08007B97A
0 ETH0.0038502314.74530446
Revoke Contract163471472023-01-06 10:28:231175 days ago1673000903IN
0xAFEDA1c4...08007B97A
0 ETH0.0010400515.77032896
Revoke Contract163471452023-01-06 10:27:591175 days ago1673000879IN
0xAFEDA1c4...08007B97A
0 ETH0.0013293915.97182617
Allow Contract163471312023-01-06 10:25:111175 days ago1673000711IN
0xAFEDA1c4...08007B97A
0 ETH0.0041363514.64785893
Allow Contract163471042023-01-06 10:19:471175 days ago1673000387IN
0xAFEDA1c4...08007B97A
0 ETH0.004108815.73554148
Allow Contract163369992023-01-05 0:26:111177 days ago1672878371IN
0xAFEDA1c4...08007B97A
0 ETH0.0054995721.05408448
Allow Contract163296682023-01-03 23:53:351178 days ago1672790015IN
0xAFEDA1c4...08007B97A
0 ETH0.004350116.65355675
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer162480742022-12-23 14:39:351189 days ago1671806375
0xAFEDA1c4...08007B97A
0.3 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.