ETH Price: $3,634.56 (-0.41%)
 

Overview

Max Total Supply

21 YFLA

Holders

12

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

Balance
3 YFLA
0x18f8fdecf6b053619ab730ff34f312b31efe6544
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
YFLArt

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

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

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

// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

/*
 * @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 GSN 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 payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File: @openzeppelin/contracts/introspection/IERC165.sol

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

// File: @openzeppelin/contracts/token/ERC721/IERC721.sol

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

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

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

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

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

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, 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 be 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * 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 Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

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

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

// File: @openzeppelin/contracts/token/ERC721/IERC721Metadata.sol

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {

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

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

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

// File: @openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {

    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol

/**
 * @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 `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
}

// File: @openzeppelin/contracts/introspection/ERC165.sol

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
abstract contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

// File: @openzeppelin/contracts/math/SafeMath.sol

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

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

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 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");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // 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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

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

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint256(_at(set._inner, index)));
    }


    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

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

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableMap for EnumerableMap.UintToAddressMap;
 *
 *     // Declare a set state variable
 *     EnumerableMap.UintToAddressMap private myMap;
 * }
 * ```
 *
 * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are
 * supported.
 */
library EnumerableMap {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Map type with
    // bytes32 keys and values.
    // The Map implementation uses private functions, and user-facing
    // implementations (such as Uint256ToAddressMap) are just wrappers around
    // the underlying Map.
    // This means that we can only create new EnumerableMaps for types that fit
    // in bytes32.

    struct MapEntry {
        bytes32 _key;
        bytes32 _value;
    }

    struct Map {
        // Storage of map keys and values
        MapEntry[] _entries;

        // Position of the entry defined by a key in the `entries` array, plus 1
        // because index 0 means a key is not in the map.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map._indexes[key];

        if (keyIndex == 0) { // Equivalent to !contains(map, key)
            map._entries.push(MapEntry({ _key: key, _value: value }));
            // The entry is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            map._indexes[key] = map._entries.length;
            return true;
        } else {
            map._entries[keyIndex - 1]._value = value;
            return false;
        }
    }

    /**
     * @dev Removes a key-value pair from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function _remove(Map storage map, bytes32 key) private returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map._indexes[key];

        if (keyIndex != 0) { // Equivalent to contains(map, key)
            // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
            // in the array, and then remove the last entry (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = keyIndex - 1;
            uint256 lastIndex = map._entries.length - 1;

            // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            MapEntry storage lastEntry = map._entries[lastIndex];

            // Move the last entry to the index where the entry to delete is
            map._entries[toDeleteIndex] = lastEntry;
            // Update the index for the moved entry
            map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved entry was stored
            map._entries.pop();

            // Delete the index for the deleted slot
            delete map._indexes[key];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function _contains(Map storage map, bytes32 key) private view returns (bool) {
        return map._indexes[key] != 0;
    }

    /**
     * @dev Returns the number of key-value pairs in the map. O(1).
     */
    function _length(Map storage map) private view returns (uint256) {
        return map._entries.length;
    }

   /**
    * @dev Returns the key-value pair stored at position `index` in the map. O(1).
    *
    * Note that there are no guarantees on the ordering of entries inside the
    * array, and it may change when more entries are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
        require(map._entries.length > index, "EnumerableMap: index out of bounds");

        MapEntry storage entry = map._entries[index];
        return (entry._key, entry._value);
    }

    /**
     * @dev Returns the value associated with `key`.  O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function _get(Map storage map, bytes32 key) private view returns (bytes32) {
        return _get(map, key, "EnumerableMap: nonexistent key");
    }

    /**
     * @dev Same as {_get}, with a custom error message when `key` is not in the map.
     */
    function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
        uint256 keyIndex = map._indexes[key];
        require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
        return map._entries[keyIndex - 1]._value; // All indexes are 1-based
    }

    // UintToAddressMap

    struct UintToAddressMap {
        Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
        return _set(map._inner, bytes32(key), bytes32(uint256(value)));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
        return _remove(map._inner, bytes32(key));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
        return _contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToAddressMap storage map) internal view returns (uint256) {
        return _length(map._inner);
    }

   /**
    * @dev Returns the element stored at position `index` in the set. O(1).
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
        (bytes32 key, bytes32 value) = _at(map._inner, index);
        return (uint256(key), address(uint256(value)));
    }

    /**
     * @dev Returns the value associated with `key`.  O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
        return address(uint256(_get(map._inner, bytes32(key))));
    }

    /**
     * @dev Same as {get}, with a custom error message when `key` is not in the map.
     */
    function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
        return address(uint256(_get(map._inner, bytes32(key), errorMessage)));
    }
}

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

/**
 * @dev String operations.
 */
library Strings {
    /**
     * @dev Converts a `uint256` to its ASCII `string` representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        uint256 index = digits - 1;
        temp = value;
        while (temp != 0) {
            buffer[index--] = byte(uint8(48 + temp % 10));
            temp /= 10;
        }
        return string(buffer);
    }
}

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

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
    using SafeMath for uint256;
    using Address for address;
    using EnumerableSet for EnumerableSet.UintSet;
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using Strings for uint256;

    // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // Mapping from holder address to their (enumerable) set of owned tokens
    mapping (address => EnumerableSet.UintSet) private _holderTokens;

    // Enumerable mapping from token ids to their owners
    EnumerableMap.UintToAddressMap private _tokenOwners;

    // Mapping from token ID to approved address
    mapping (uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Optional mapping for token URIs
    mapping (uint256 => string) private _tokenURIs;

    // Base URI
    string private _baseURI;

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    /*
     *     bytes4(keccak256('name()')) == 0x06fdde03
     *     bytes4(keccak256('symbol()')) == 0x95d89b41
     *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
     *
     *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
     */
    bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

    /*
     *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
     *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
     *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
     *
     *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
     */
    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor (string memory name_, string memory symbol_) public {
        _name = name_;
        _symbol = symbol_;

        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
        _registerInterface(_INTERFACE_ID_ERC721_METADATA);
        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");

        return _holderTokens[owner].length();
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view override returns (address) {
        return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory _tokenURI = _tokenURIs[tokenId];

        // If there is no base URI, return the token URI.
        if (bytes(_baseURI).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(_baseURI, _tokenURI));
        }
        // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
        return string(abi.encodePacked(_baseURI, tokenId.toString()));
    }

    /**
    * @dev Returns the base URI set via {_setBaseURI}. This will be
    * automatically added as a prefix in {tokenURI} to each token's URI, or
    * to the token ID if no specific URI is set for that token ID.
    */
    function baseURI() public view returns (string memory) {
        return _baseURI;
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) {
        return _holderTokens[owner].at(index);
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
        return _tokenOwners.length();
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view override returns (uint256) {
        (uint256 tokenId, ) = _tokenOwners.at(index);
        return tokenId;
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        require(operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

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

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @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.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        return _tokenOwners.contains(tokenId);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     d*
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _holderTokens[to].add(tokenId);

        _tokenOwners.set(tokenId, to);

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

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        // Clear metadata (if any)
        if (bytes(_tokenURIs[tokenId]).length != 0) {
            delete _tokenURIs[tokenId];
        }

        _holderTokens[owner].remove(tokenId);

        _tokenOwners.remove(tokenId);

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal virtual {
        require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _holderTokens[from].remove(tokenId);
        _holderTokens[to].add(tokenId);

        _tokenOwners.set(tokenId, to);

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
        require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
        _tokenURIs[tokenId] = _tokenURI;
    }

    /**
     * @dev Internal function to set the base URI for all token IDs. It is
     * automatically added as a prefix to the value returned in {tokenURI},
     * or to the token ID if {tokenURI} is empty.
     */
    function _setBaseURI(string memory baseURI_) internal virtual {
        _baseURI = baseURI_;
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        private returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }
        bytes memory returndata = to.functionCall(abi.encodeWithSelector(
            IERC721Receiver(to).onERC721Received.selector,
            _msgSender(),
            from,
            tokenId,
            _data
        ), "ERC721: transfer to non ERC721Receiver implementer");
        bytes4 retval = abi.decode(returndata, (bytes4));
        return (retval == _ERC721_RECEIVED);
    }

    function _approve(address to, uint256 tokenId) private {
        _tokenApprovals[tokenId] = to;
        emit Approval(ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
}

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

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

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

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

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

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

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

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

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * 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 is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @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 {
        emit OwnershipTransferred(_owner, address(0));
        _owner = 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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// File: contracts/lib/Roles.sol

/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
    struct Role {
        mapping (address => bool) bearer;
    }

    /**
     * @dev Give an account access to this role.
     */
    function add(Role storage role, address account) internal {
        require(!has(role, account), "Roles: account already has role");
        role.bearer[account] = true;
    }

    /**
     * @dev Remove an account's access to this role.
     */
    function remove(Role storage role, address account) internal {
        require(has(role, account), "Roles: account does not have role");
        role.bearer[account] = false;
    }

    /**
     * @dev Check if an account has this role.
     * @return bool
     */
    function has(Role storage role, address account) internal view returns (bool) {
        require(account != address(0), "Roles: account is the zero address");
        return role.bearer[account];
    }
}

// File: contracts/lib/SignerRole.sol

contract SignerRole is Context {
    using Roles for Roles.Role;

    event SignerAdded(address indexed account);
    event SignerRemoved(address indexed account);

    Roles.Role private _signers;

    constructor () internal {
        _addSigner(_msgSender());
    }

    modifier onlySigner() {
        require(isSigner(_msgSender()), "SignerRole: caller does not have the Signer role");
        _;
    }

    function isSigner(address account) public view returns (bool) {
        return _signers.has(account);
    }

    function addSigner(address account) public onlySigner {
        _addSigner(account);
    }

    function renounceSigner() public {
        _removeSigner(_msgSender());
    }

    function _addSigner(address account) internal {
        _signers.add(account);
        emit SignerAdded(account);
    }

    function _removeSigner(address account) internal {
        _signers.remove(account);
        emit SignerRemoved(account);
    }
}

// File: contracts/IyYFL.sol

pragma experimental ABIEncoderV2;

interface IyYFL is IERC20 {
    // Event emitted when a new proposal is created
    event ProposalCreated(
        uint256 id,
        address indexed proposer,
        address[] targets,
        uint256[] values,
        string[] signatures,
        bytes[] calldatas,
        uint256 startBlock,
        uint256 endBlock,
        string description
    );
    // Event emitted when a vote has been cast on a proposal
    event VoteCast(address indexed voter, uint256 proposalId, bool support, uint256 votes);
    // Event emitted when a proposal has been executed
    // Success=true if all actions were executed successfully
    // Success=false if not all actions were executed successfully (executeProposal will not revert)
    event ProposalExecuted(uint256 id, bool success);

    // Maximum number of actions that can be included in a proposal
    function MAX_OPERATIONS() external pure returns (uint256);

    // https://etherscan.io/token/0x28cb7e841ee97947a86B06fA4090C8451f64c0be
    function YFL() external pure returns (IERC20);

    struct Proposal {
        // Address that created the proposal
        address proposer;
        // Number of votes in support of the proposal by a particular address
        mapping(address => uint256) forVotes;
        // Number of votes against the proposal by a particular address
        mapping(address => uint256) againstVotes;
        // Total number of votes in support of the proposal
        uint256 totalForVotes;
        // Total number of votes against the proposal
        uint256 totalAgainstVotes;
        // Number of votes in support of a proposal required for a quorum to be reached and for a vote to succeed
        uint256 quorumVotes;
        // Block at which voting ends: votes must be cast prior to this block
        uint256 endBlock;
        // Ordered list of target addresses for calls to be made on
        address[] targets;
        // Ordered list of ETH values (i.e. msg.value) to be passed to the calls to be made
        uint256[] values;
        // Ordered list of function signatures to be called
        string[] signatures;
        // Ordered list of calldata to be passed to each call
        bytes[] calldatas;
        // Flag marking whether the proposal has been executed
        bool executed;
    }

    // Number of blocks after staking when the early withdrawal fee stops applying
    function blocksForNoWithdrawalFee() external view returns (uint256);

    // Fee for withdrawing before blocksForNoWithdrawalFee have passed, divide by 1,000,000 to get decimal form
    function earlyWithdrawalFeePercent() external view returns (uint256);

    function earlyWithdrawalFeeExpiry(address) external view returns (uint256);

    function treasury() external view returns (address);

    // Share of early withdrawal fee that goes to treasury (remainder goes to governance),
    // divide by 1,000,000 to get decimal form
    function treasuryEarlyWithdrawalFeeShare() external view returns (uint256);

    // Smart contract that exchanges ERC20 tokens for YFL
    function yflPurchaser() external view returns (address);

    // Amount of an address's stake that is locked for voting
    function voteLockAmount(address) external view returns (uint256);

    // Block number when an address's vote-locked amount will be unlock
    function voteLockExpiry(address) external view returns (uint256);

    function hasActiveProposal(address) external view returns (bool);

    function proposals(uint256 id)
        external
        view
        returns (
            address proposer,
            uint256 totalForVotes,
            uint256 totalAgainstVotes,
            uint256 quorumVotes,
            uint256 endBlock,
            bool executed
        );

    // Number of proposals created, used as the id for the next proposal
    function proposalCount() external view returns (uint256);

    // Length of voting period in blocks
    function votingPeriodBlocks() external view returns (uint256);

    function minYflForProposal() external view returns (uint256);

    // Need to divide by 1,000,000
    function quorumPercent() external view returns (uint256);

    // Need to divide by 1,000,000
    function voteThresholdPercent() external view returns (uint256);

    // Number of blocks after voting ends where proposals are allowed to be executed
    function executionPeriodBlocks() external view returns (uint256);

    function stake(uint256 amount) external;

    // call this to swap token revenue to YFL for YFL stakers
    function convertTokensToYfl(address[] calldata tokens, uint256[] calldata amounts) external;

    function withdraw(uint256 shares) external;

    function getPricePerFullShare() external view returns (uint256);

    function getStakeYflValue(address staker) external view returns (uint256);

    function propose(
        address[] calldata targets,
        uint256[] calldata values,
        string[] calldata signatures,
        bytes[] calldata calldatas,
        string calldata description
    ) external returns (uint256 id);

    function vote(
        uint256 id,
        bool support,
        uint256 voteAmount
    ) external;

    function executeProposal(uint256 id) external payable;

    function getVotes(uint256 proposalId, address voter) external view returns (bool support, uint256 voteAmount);

    function getProposalCalls(uint256 proposalId)
        external
        view
        returns (
            address[] memory targets,
            uint256[] memory values,
            string[] memory signatures,
            bytes[] memory calldatas
        );

    function setTreasury(address) external;

    function setTreasuryEarlyWithdrawalFeeShare(uint256) external;

    function setYflPurchaser(address) external;

    function setBlocksForNoWithdrawalFee(uint256) external;

    function setEarlyWithdrawalFeePercent(uint256) external;

    function setVotingPeriodBlocks(uint256) external;

    function setMinYflForProposal(uint256) external;

    function setQuorumPercent(uint256) external;

    function setVoteThresholdPercent(uint256) external;

    function setExecutionPeriodBlocks(uint256) external;
}

// File: contracts/YFLArt.sol

/**
 * @title YFLArt
 * @notice The YFLArt NFT contract allows NFTs to be registered and bought
 * which are backed by a specific amount of YFL. NFTs can also optionally
 * charge a fee of any token that must be paid on purchase.
 */
contract YFLArt is ERC721, Ownable, SignerRole {
  using Address for address;
  using SafeERC20 for IERC20;

  IyYFL public immutable yYFL;
  uint256 public yflLocked;

  struct Registry {
    string tokenURI;
    address originalBuyer;
    address artist;
    address reseller;
    address paymentToken;
    uint256 paymentAmount;
    uint256 yflAmount;
  }

  mapping(uint256 => Registry) public registry;
  // The YFL-backed balances of each NFT
  mapping(uint256 => uint256) public balances;

  event Registered(
    uint256 _tokenId,
    string _tokenURI,
    address _originalBuyer,
    address _artist,
    address _paymentToken,
    uint256 _paymentAmount,
    uint256 _yflAmount
  );

  /**
   * @param _name The name of the NFT
   * @param _symbol The symbol of the NFT
   * @param _baseURI The base URI of the NFT
   * @param _yYFL The address of the yYFL governance contract
   */
  constructor(
    string memory _name,
    string memory _symbol,
    string memory _baseURI,
    address _yYFL
  )
    public
    ERC721(_name, _symbol)
  {
    yYFL = IyYFL(_yYFL);
    _setBaseURI(_baseURI);
  }

  /**
   * EXTERNAL FUNCTIONS
   * (SIGNER FUNCTIONS)
   */

  /**
   * @notice Called by a signer to register the pre-sale of an NFT
   * @param _tokenId The unique ID of the NFT
   * @param _v Recovery ID of the signer
   * @param _r First 32 bytes of the signature
   * @param _s Second 32 bytes of the signature
   * @param _tokenURI The token URI of the NFT
   * @param _originalBuyer The address of the original buyer
   * @param _artist The address of the artist
   * @param _paymentToken The address of the token for payment
   * @param _paymentAmount The amount of payment of the payment token
   * @param _yflAmount The amount of YFL backing the NFT
   */
  function signerRegister(
    uint256 _tokenId,
    uint8 _v,
    bytes32 _r,
    bytes32 _s,
    string memory _tokenURI,
    address _originalBuyer,
    address _artist,
    address _paymentToken,
    uint256 _paymentAmount,
    uint256 _yflAmount
  )
    external
  {
    require(isSigner(ecrecover(
        keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32",
        keccak256(abi.encodePacked(_tokenId)))), _v, _r, _s)),
      "!signer");
    _register(_tokenId, _tokenURI, _originalBuyer, _artist, _paymentToken, _paymentAmount, _yflAmount);
  }

  /**
   * EXTERNAL FUNCTIONS
   * (OWNER FUNCTIONS)
   */

  /**
   * @notice Recovers stuck tokens from this contract. Does not allow pulling locked YFL out.
   * @param _token The token to withdraw
   * @param _receiver The address to receive the token
   * @param _amount The amount of tokens to withdraw
   */
  function recoverStuckTokens(IERC20 _token, address _receiver, uint256 _amount) external onlyOwner() {
    if (address(_token) == address(yYFL.YFL())) {
      require(_amount <= yYFL.YFL().balanceOf(address(this)).sub(yflLocked), "!_amount");
    }
    _token.transfer(_receiver, _amount);
  }

  /**
   * @notice Called by the owner to register the pre-sale of an NFT
   * @param _tokenId The unique ID of the NFT
   * @param _tokenURI The token URI of the NFT
   * @param _originalBuyer The address of the original buyer
   * @param _artist The address of the artist
   * @param _paymentToken The address of the token for payment
   * @param _paymentAmount The amount of payment of the payment token
   * @param _yflAmount The amount of YFL backing the NFT
   */
  function register(
    uint256 _tokenId,
    string memory _tokenURI,
    address _originalBuyer,
    address _artist,
    address _paymentToken,
    uint256 _paymentAmount,
    uint256 _yflAmount
  )
    external
    onlyOwner()
  {
    _register(_tokenId, _tokenURI, _originalBuyer, _artist, _paymentToken, _paymentAmount, _yflAmount);
  }

  /**
   * @notice Called by the owner to set the baseURI of the NFT
   * @param _baseURI The base URI of the NFT
   */
  function setBaseURI(string memory _baseURI) external onlyOwner() {
    _setBaseURI(_baseURI);
  }

  /**
   * EXTERNAL FUNCTIONS
   * (USER FUNCTIONS)
   */

  /**
   * @notice Called by a user to buy a registered NFT
   * @param _tokenId The ID of the registered NFT
   */
  function buy(
    uint256 _tokenId
  )
    external
  {
    Registry memory token = registry[_tokenId];
    require(token.yflAmount > 0, "!registered");
    yYFL.YFL().safeTransferFrom(msg.sender, address(this), token.yflAmount);
    IERC20(token.paymentToken).safeTransferFrom(msg.sender, address(this), token.paymentAmount);
    balances[_tokenId] = token.yflAmount;
    yflLocked = yflLocked.add(token.yflAmount);
    if (!_exists(_tokenId)) {
      if (token.originalBuyer != address(0)) {
        require(msg.sender == token.originalBuyer, "!originalBuyer");
      }
      uint256 serviceFee = token.paymentAmount.div(100).mul(80);
      uint256 artistFee = token.paymentAmount.sub(serviceFee);
      IERC20(token.paymentToken).safeTransfer(yYFL.treasury(), serviceFee);
      IERC20(token.paymentToken).safeTransfer(token.artist, artistFee);
      _mint(msg.sender, _tokenId);
      _setTokenURI(_tokenId, token.tokenURI);
    } else {
      require(ownerOf(_tokenId) == address(this), "!buy");
      uint256 resellerFee = token.paymentAmount.div(100).mul(90);
      uint256 remainingFee = token.paymentAmount.sub(resellerFee);
      remainingFee = remainingFee.div(2);
      IERC20(token.paymentToken).safeTransfer(token.reseller, resellerFee);
      IERC20(token.paymentToken).safeTransfer(yYFL.treasury(), remainingFee);
      IERC20(token.paymentToken).safeTransfer(token.artist, remainingFee);
      _transfer(address(this), msg.sender, _tokenId);
    }
  }

  /**
   * @notice Called by the owner of the NFT to stake the backed YFL in governance
   * @param _tokenId The ID of the registered NFT
   */
  function stake(uint256 _tokenId) external {
    require(msg.sender == ownerOf(_tokenId), "!ownerOf");
    uint256 amount = balances[_tokenId];
    require(amount > 0, "staked");
    delete balances[_tokenId];
    yflLocked = yflLocked.sub(amount);
    uint256 shares = _stake(amount);
    IERC20(yYFL).transfer(msg.sender, shares);
  }

  /**
   * @notice Called by the owner of the NFT to resell the NFT
   * @param _tokenId The ID of the registered NFT
   * @param _paymentToken The address of the token for payment
   * @param _paymentAmount The amount of payment of the payment token
   */
  function resell(
    uint256 _tokenId,
    address _paymentToken,
    uint256 _paymentAmount
  )
    external
  {
    transferFrom(msg.sender, address(this), _tokenId);
    registry[_tokenId].reseller = msg.sender;
    registry[_tokenId].paymentToken = _paymentToken;
    registry[_tokenId].paymentAmount = _paymentAmount;
    uint256 amount = registry[_tokenId].yflAmount;
    yflLocked = yflLocked.sub(amount);
    delete balances[_tokenId];
    yYFL.YFL().safeTransfer(msg.sender, amount);
  }

  /**
   * PUBLIC FUNCTIONS
   * (USER FUNCTIONS)
   */

  /**
   * @notice Can be called by any address to fund an unfunded NFT with YFL
   * @param _tokenId The ID of the registered NFT
   */
  function fund(uint256 _tokenId) public {
    require(_exists(_tokenId), "!exists");
    require(!isFunded(_tokenId), "isFunded");
    uint256 amount = registry[_tokenId].yflAmount;
    balances[_tokenId] = amount;
    yflLocked = yflLocked.add(amount);
    yYFL.YFL().safeTransferFrom(msg.sender, address(this), amount);
  }

  /**
   * VIEWS
   */

  /**
   * @notice Can be called by any address to check if a NFT is funded
   * @param _tokenId The ID of the registered NFT
   */
  function isFunded(uint256 _tokenId) public view returns (bool) {
    return registry[_tokenId].yflAmount == balances[_tokenId];
  }

  /**
   * INTERNAL FUNCTIONS
   */

  /**
   * @notice This function is called before any NFT token transfer
   * @dev Requires the NFT to be backed by YFL before transferring
   */
  function _beforeTokenTransfer(
    address _from,
    address _to,
    uint256 _tokenId
  )
    internal
    override
  {
    if (!isFunded(_tokenId)) {
      fund(_tokenId);
    }
  }

  /**
   * @notice Shared register function
   */
  function _register(
    uint256 _tokenId,
    string memory _tokenURI,
    address _originalBuyer,
    address _artist,
    address _paymentToken,
    uint256 _paymentAmount,
    uint256 _yflAmount
  )
    internal
  {
    require(!_exists(_tokenId), "exists");
    require(registry[_tokenId].yflAmount == 0, "registered");
    require(_yflAmount > 0, "!_yflAmount");
    require(_artist != address(0), "!_artist");
    registry[_tokenId] = Registry({
      tokenURI: _tokenURI,
      originalBuyer: _originalBuyer,
      artist: _artist,
      reseller: address(0),
      paymentToken: _paymentToken,
      paymentAmount: _paymentAmount,
      yflAmount: _yflAmount
    });
    emit Registered(
      _tokenId,
      _tokenURI,
      _originalBuyer,
      _artist,
      _paymentToken,
      _paymentAmount,
      _yflAmount
    );
  }

  /**
   * @notice Internal function to help with getting shares from yYFL
   */
  function _stake(uint256 _amount) internal returns (uint256 shares) {
    yYFL.YFL().approve(address(yYFL), 0);
    yYFL.YFL().approve(address(yYFL), _amount);
    uint256 sharesBefore = yYFL.balanceOf(address(this));
    yYFL.stake(_amount);
    uint256 sharesAfter = yYFL.balanceOf(address(this));
    shares = sharesAfter.sub(sharesBefore);
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_baseURI","type":"string"},{"internalType":"address","name":"_yYFL","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"string","name":"_tokenURI","type":"string"},{"indexed":false,"internalType":"address","name":"_originalBuyer","type":"address"},{"indexed":false,"internalType":"address","name":"_artist","type":"address"},{"indexed":false,"internalType":"address","name":"_paymentToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_paymentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_yflAmount","type":"uint256"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"SignerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"SignerRemoved","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":"address","name":"account","type":"address"}],"name":"addSigner","outputs":[],"stateMutability":"nonpayable","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":"uint256","name":"","type":"uint256"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"fund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"_tokenId","type":"uint256"}],"name":"isFunded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverStuckTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_tokenURI","type":"string"},{"internalType":"address","name":"_originalBuyer","type":"address"},{"internalType":"address","name":"_artist","type":"address"},{"internalType":"address","name":"_paymentToken","type":"address"},{"internalType":"uint256","name":"_paymentAmount","type":"uint256"},{"internalType":"uint256","name":"_yflAmount","type":"uint256"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"registry","outputs":[{"internalType":"string","name":"tokenURI","type":"string"},{"internalType":"address","name":"originalBuyer","type":"address"},{"internalType":"address","name":"artist","type":"address"},{"internalType":"address","name":"reseller","type":"address"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"uint256","name":"yflAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_paymentToken","type":"address"},{"internalType":"uint256","name":"_paymentAmount","type":"uint256"}],"name":"resell","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":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"string","name":"_tokenURI","type":"string"},{"internalType":"address","name":"_originalBuyer","type":"address"},{"internalType":"address","name":"_artist","type":"address"},{"internalType":"address","name":"_paymentToken","type":"address"},{"internalType":"uint256","name":"_paymentAmount","type":"uint256"},{"internalType":"uint256","name":"_yflAmount","type":"uint256"}],"name":"signerRegister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","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":[],"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":[],"name":"yYFL","outputs":[{"internalType":"contract IyYFL","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yflLocked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b5060405162004304380380620043048339810160408190526200003491620003eb565b8383620000486301ffc9a760e01b62000142565b81516200005d906006906020850190620002a8565b50805162000073906007906020840190620002a8565b50620000866380ac58cd60e01b62000142565b62000098635b5e139f60e01b62000142565b620000aa63780e9d6360e01b62000142565b5060009050620000b96200019d565b600a80546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506200011b620001156200019d565b620001a1565b6001600160601b0319606082901b166080526200013882620001f3565b5050505062000549565b6001600160e01b03198082161415620001785760405162461bcd60e51b81526004016200016f90620004d0565b60405180910390fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b3390565b620001bc81600b6200020c60201b620018d71790919060201c565b6040516001600160a01b038216907f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2490600090a250565b805162000208906009906020840190620002a8565b5050565b6200021882826200025d565b15620002385760405162461bcd60e51b81526004016200016f9062000499565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b60006001600160a01b038216620002885760405162461bcd60e51b81526004016200016f9062000507565b506001600160a01b03166000908152602091909152604090205460ff1690565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002eb57805160ff19168380011785556200031b565b828001600101855582156200031b579182015b828111156200031b578251825591602001919060010190620002fe565b50620003299291506200032d565b5090565b5b808211156200032957600081556001016200032e565b600082601f83011262000355578081fd5b81516001600160401b03808211156200036c578283fd5b6040516020601f8401601f19168201810183811183821017156200038e578586fd5b80604052508194508382528681858801011115620003ab57600080fd5b600092505b83831015620003cf5785830181015182840182015291820191620003b0565b83831115620003e15760008185840101525b5050505092915050565b6000806000806080858703121562000401578384fd5b84516001600160401b038082111562000418578586fd5b620004268883890162000344565b955060208701519150808211156200043c578485fd5b6200044a8883890162000344565b9450604087015191508082111562000460578384fd5b506200046f8782880162000344565b606087015190935090506001600160a01b03811681146200048e578182fd5b939692955090935050565b6020808252601f908201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604082015260600190565b6020808252601c908201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604082015260600190565b60208082526022908201527f526f6c65733a206163636f756e7420697320746865207a65726f206164647265604082015261737360f01b606082015260800190565b60805160601c613d52620005b26000398061073f528061093d5280610d375280610e305280610ee0528061125a5280611427528061156752806116ed5280611e305280611ecf5280611f62528061200152806120ab528061214a52806121ca5250613d526000f3fe608060405234801561001057600080fd5b50600436106101ac5760003560e01c806301ffc9a7146101b1578063041dc891146101da57806305dca80e146101ef57806306fdde0314610204578063081812fc14610219578063095ea7b31461023957806318160ddd1461024c57806323b872dd146102545780632f745c591461026757806334a354ce1461027a57806342842e0e146102825780634903b0d1146102955780634f6ccce7146102a857806355f804b3146102bb5780635893253c146102ce5780635beac899146102f45780636352211e146103075780636c0360eb1461031a57806370a0823114610322578063715018a6146103355780637df73e271461033d5780638da5cb5b146103505780638f8e42f61461035857806395d89b411461036b578063a22cb46514610373578063a694fc3a14610386578063b88d4fde14610399578063bfa883ab146103ac578063c2c6c677146103bf578063c87b56dd146103d2578063ca1d209d146103e5578063d96a094a146103f8578063e5c8b03d1461040b578063e985e9c514610413578063eb12d61e14610426578063f2fde38b14610439575b600080fd5b6101c46101bf366004612ec1565b61044c565b6040516101d1919061325a565b60405180910390f35b6101e261046f565b6040516101d191906131c3565b6102026101fd366004613011565b610475565b005b61020c610558565b6040516101d19190613283565b61022c610227366004612f2b565b6105ee565b6040516101d191906131cc565b610202610247366004612e7a565b610631565b6101e26106c9565b610202610262366004612da4565b6106da565b6101e2610275366004612e7a565b610712565b61022c61073d565b610202610290366004612da4565b610761565b6101e26102a3366004612f2b565b61077c565b6101e26102b6366004612f2b565b61078e565b6102026102c9366004612ef9565b6107a4565b6102e16102dc366004612f2b565b6107e5565b6040516101d19796959493929190613296565b610202610302366004612f5b565b6108bb565b61022c610315366004612f2b565b6109e2565b61020c610a0a565b6101e2610330366004612d34565b610a6b565b610202610ab4565b6101c461034b366004612d34565b610b21565b61022c610b2e565b6101c4610366366004612f2b565b610b3d565b61020c610b5f565b610202610381366004612e4d565b610bc0565b610202610394366004612f2b565b610c8e565b6102026103a7366004612de4565b610dc0565b6102026103ba366004612da4565b610df9565b6102026103cd366004612f81565b61103d565b61020c6103e0366004612f2b565b61108a565b6102026103f3366004612f2b565b6111d4565b610202610406366004612f2b565b6112fe565b6102026117c2565b6101c4610421366004612d6c565b6117d4565b610202610434366004612d34565b611802565b610202610447366004612d34565b611832565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b600c5481565b61051860018b60405160200161048b91906131c3565b604051602081830303815290604052805190602001206040516020016104b19190613193565b604051602081830303815290604052805190602001208b8b8b604051600081526020016040526040516104e79493929190613265565b6020604051602081039080840390855afa158015610509573d6000803e3d6000fd5b50505060206040510351610b21565b61053d5760405162461bcd60e51b8152600401610534906137f5565b60405180910390fd5b61054c8a878787878787611923565b50505050505050505050565b60068054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105e45780601f106105b9576101008083540402835291602001916105e4565b820191906000526020600020905b8154815290600101906020018083116105c757829003601f168201915b5050505050905090565b60006105f982611aef565b6106155760405162461bcd60e51b815260040161053490613857565b506000908152600460205260409020546001600160a01b031690565b600061063c826109e2565b9050806001600160a01b0316836001600160a01b031614156106705760405162461bcd60e51b815260040161053490613a26565b806001600160a01b0316610682611afc565b6001600160a01b0316148061069e575061069e81610421611afc565b6106ba5760405162461bcd60e51b815260040161053490613676565b6106c48383611b00565b505050565b60006106d56002611b6e565b905090565b6106eb6106e5611afc565b82611b79565b6107075760405162461bcd60e51b815260040161053490613adb565b6106c4838383611bfe565b6001600160a01b03821660009081526001602052604081206107349083611cfa565b90505b92915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106c483838360405180602001604052806000815250610dc0565b600e6020526000908152604090205481565b60008061079c600284611d06565b509392505050565b6107ac611afc565b600a546001600160a01b039081169116146107d95760405162461bcd60e51b815260040161053490613917565b6107e281611d22565b50565b600d6020908152600091825260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845290929183919083018282801561087c5780601f106108515761010080835404028352916020019161087c565b820191906000526020600020905b81548152906001019060200180831161085f57829003601f168201915b505050506001830154600284015460038501546004860154600587015460069097015495966001600160a01b0394851696938516955091841693169187565b6108c63330856106da565b6000838152600d60205260409020600381018054336001600160a01b0319918216179091556004820180549091166001600160a01b0385161790556005810182905560060154600c546109199082611d35565b600c81905550600e6000858152602001908152602001600020600090556109dc33827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b15801561099457600080fd5b505afa1580156109a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cc9190612d50565b6001600160a01b03169190611d77565b50505050565b600061073782604051806060016040528060298152602001613cb46029913960029190611dcd565b60098054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105e45780601f106105b9576101008083540402835291602001916105e4565b60006001600160a01b038216610a935760405162461bcd60e51b8152600401610534906136ce565b6001600160a01b038216600090815260016020526040902061073790611b6e565b610abc611afc565b600a546001600160a01b03908116911614610ae95760405162461bcd60e51b815260040161053490613917565b600a546040516000916001600160a01b031690600080516020613cdd833981519152908390a3600a80546001600160a01b0319169055565b6000610737600b83611de4565b600a546001600160a01b031690565b6000908152600e6020908152604080832054600d909252909120600601541490565b60078054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105e45780601f106105b9576101008083540402835291602001916105e4565b610bc8611afc565b6001600160a01b0316826001600160a01b03161415610bf95760405162461bcd60e51b815260040161053490613527565b8060056000610c06611afc565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155610c4a611afc565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610c82919061325a565b60405180910390a35050565b610c97816109e2565b6001600160a01b0316336001600160a01b031614610cc75760405162461bcd60e51b8152600401610534906134c1565b6000818152600e602052604090205480610cf35760405162461bcd60e51b8152600401610534906134a1565b6000828152600e6020526040812055600c54610d0f9082611d35565b600c556000610d1d82611e2c565b60405163a9059cbb60e01b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90610d6e903390859060040161321d565b602060405180830381600087803b158015610d8857600080fd5b505af1158015610d9c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109dc9190612ea5565b610dd1610dcb611afc565b83611b79565b610ded5760405162461bcd60e51b815260040161053490613adb565b6109dc8484848461225c565b610e01611afc565b600a546001600160a01b03908116911614610e2e5760405162461bcd60e51b815260040161053490613917565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b158015610e8757600080fd5b505afa158015610e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebf9190612d50565b6001600160a01b0316836001600160a01b0316141561100f57610ff0600c547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190612d50565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610f9a91906131cc565b60206040518083038186803b158015610fb257600080fd5b505afa158015610fc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fea9190612f43565b90611d35565b81111561100f5760405162461bcd60e51b81526004016105349061359d565b60405163a9059cbb60e01b81526001600160a01b0384169063a9059cbb90610d6e908590859060040161321d565b611045611afc565b600a546001600160a01b039081169116146110725760405162461bcd60e51b815260040161053490613917565b61108187878787878787611923565b50505050505050565b606061109582611aef565b6110b15760405162461bcd60e51b8152600401610534906139d7565b60008281526008602090815260409182902080548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156111465780601f1061111b57610100808354040283529160200191611146565b820191906000526020600020905b81548152906001019060200180831161112957829003601f168201915b50506009549394505050506002600019610100600184161502019091160461116f57905061046a565b8051156111a15760098160405160200161118a929190613112565b60405160208183030381529060405291505061046a565b60096111ac8461228f565b6040516020016111bd929190613112565b604051602081830303815290604052915050919050565b6111dd81611aef565b6111f95760405162461bcd60e51b81526004016105349061355a565b61120281610b3d565b1561121f5760405162461bcd60e51b815260040161053490613bad565b6000818152600d6020908152604080832060060154600e909252909120819055600c5461124c9082612369565b600c819055506112fa3330837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b1580156112b157600080fd5b505afa1580156112c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e99190612d50565b6001600160a01b031692919061238e565b5050565b611306612bdd565b6000828152600d602090815260409182902082518154600260018216156101009081026000190190921604601f81018590049094028201810190945260e081018381529093919284928491908401828280156113a35780601f10611378576101008083540402835291602001916113a3565b820191906000526020600020905b81548152906001019060200180831161138657829003601f168201915b505050918352505060018201546001600160a01b0390811660208301526002830154811660408301526003830154811660608301526004830154166080820152600582015460a082015260069091015460c09182015281015190915061141b5760405162461bcd60e51b8152600401610534906135bf565b61147e33308360c001517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b1580156112b157600080fd5b6114a633308360a0015184608001516001600160a01b031661238e909392919063ffffffff16565b60c0810180516000848152600e602052604090205551600c546114c891612369565b600c556114d482611aef565b6116505760208101516001600160a01b0316156115205780602001516001600160a01b0316336001600160a01b0316146115205760405162461bcd60e51b8152600401610534906138ef565b6000611545605061153f60648560a001516123af90919063ffffffff16565b906123ee565b90506000611560828460a00151611d3590919063ffffffff16565b905061160b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166361d027b36040518163ffffffff1660e01b815260040160206040518083038186803b1580156115be57600080fd5b505afa1580156115d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f69190612d50565b60808501516001600160a01b03169084611d77565b61163183604001518285608001516001600160a01b0316611d779092919063ffffffff16565b61163b3385612428565b6116498484600001516124da565b50506112fa565b3061165a836109e2565b6001600160a01b0316146116805760405162461bcd60e51b8152600401610534906133d2565b600061169f605a61153f60648560a001516123af90919063ffffffff16565b905060006116ba828460a00151611d3590919063ffffffff16565b90506116c78160026123af565b606084015160808501519192506116e8916001600160a01b03169084611d77565b6117917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166361d027b36040518163ffffffff1660e01b815260040160206040518083038186803b15801561174457600080fd5b505afa158015611758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177c9190612d50565b60808501516001600160a01b03169083611d77565b6117b783604001518285608001516001600160a01b0316611d779092919063ffffffff16565b6109dc303386611bfe565b6117d26117cd611afc565b61251e565b565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61180d61034b611afc565b6118295760405162461bcd60e51b815260040161053490613a67565b6107e281612560565b61183a611afc565b600a546001600160a01b039081169116146118675760405162461bcd60e51b815260040161053490613917565b6001600160a01b03811661188d5760405162461bcd60e51b8152600401610534906133f0565b600a546040516001600160a01b03808416921690600080516020613cdd83398151915290600090a3600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6118e18282611de4565b156118fe5760405162461bcd60e51b815260040161053490613349565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b61192c87611aef565b156119495760405162461bcd60e51b8152600401610534906132e7565b6000878152600d6020526040902060060154156119785760405162461bcd60e51b815260040161053490613ab7565b600081116119985760405162461bcd60e51b81526004016105349061379b565b6001600160a01b0384166119be5760405162461bcd60e51b81526004016105349061357b565b6040805160e0810182528781526001600160a01b0380881660208084019190915287821683850152600060608401819052918716608084015260a0830186905260c083018590528a8252600d81529290208151805192939192611a249284920190612c19565b5060208201516001820180546001600160a01b03199081166001600160a01b03938416179091556040808501516002850180548416918516919091179055606085015160038501805484169185169190911790556080850151600485018054909316931692909217905560a0830151600583015560c090920151600690910155517f676c6ca8bd2bf6f3412482eaa1dc0592fa9a9dd8f822574666177e537aafa19e90611ade908990899089908990899089908990613bcf565b60405180910390a150505050505050565b60006107376002836125a2565b3390565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611b35826109e2565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000610737826125ae565b6000611b8482611aef565b611ba05760405162461bcd60e51b81526004016105349061362a565b6000611bab836109e2565b9050806001600160a01b0316846001600160a01b03161480611be65750836001600160a01b0316611bdb846105ee565b6001600160a01b0316145b80611bf65750611bf681856117d4565b949350505050565b826001600160a01b0316611c11826109e2565b6001600160a01b031614611c375760405162461bcd60e51b81526004016105349061398e565b6001600160a01b038216611c5d5760405162461bcd60e51b8152600401610534906134e3565b611c688383836125b2565b611c73600082611b00565b6001600160a01b0383166000908152600160205260409020611c9590826125c8565b506001600160a01b0382166000908152600160205260409020611cb890826125d4565b50611cc5600282846125e0565b5080826001600160a01b0316846001600160a01b0316600080516020613cfd83398151915260405160405180910390a4505050565b600061073483836125f6565b6000808080611d15868661263b565b9097909650945050505050565b80516112fa906009906020840190612c19565b600061073483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612697565b6106c48363a9059cbb60e01b8484604051602401611d9692919061321d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526126c3565b6000611dda848484612752565b90505b9392505050565b60006001600160a01b038216611e0c5760405162461bcd60e51b81526004016105349061394c565b506001600160a01b03166000908152602091909152604090205460ff1690565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b158015611e8757600080fd5b505afa158015611e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebf9190612d50565b6001600160a01b031663095ea7b37f000000000000000000000000000000000000000000000000000000000000000060006040518363ffffffff1660e01b8152600401611f0d92919061321d565b602060405180830381600087803b158015611f2757600080fd5b505af1158015611f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5f9190612ea5565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b158015611fb957600080fd5b505afa158015611fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ff19190612d50565b6001600160a01b031663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000846040518363ffffffff1660e01b815260040161203e92919061321d565b602060405180830381600087803b15801561205857600080fd5b505af115801561206c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120909190612ea5565b506040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a08231906120e09030906004016131cc565b60206040518083038186803b1580156120f857600080fd5b505afa15801561210c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121309190612f43565b60405163534a7e1d60e11b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a694fc3a9061217f9086906004016131c3565b600060405180830381600087803b15801561219957600080fd5b505af11580156121ad573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691506370a08231906122009030906004016131cc565b60206040518083038186803b15801561221857600080fd5b505afa15801561222c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122509190612f43565b9050611bf68183611d35565b612267848484611bfe565b612273848484846127b1565b6109dc5760405162461bcd60e51b815260040161053490613380565b6060816122b457506040805180820190915260018152600360fc1b602082015261046a565b8160005b81156122cc57600101600a820491506122b8565b6060816001600160401b03811180156122e457600080fd5b506040519080825280601f01601f19166020018201604052801561230f576020820181803683370190505b50859350905060001982015b831561236057600a840660300160f81b8282806001900393508151811061233e57fe5b60200101906001600160f81b031916908160001a905350600a8404935061231b565b50949350505050565b6000828201838110156107345760405162461bcd60e51b81526004016105349061346c565b6109dc846323b872dd60e01b858585604051602401611d9693929190613236565b600061073483836040518060400160405280601a815260200179536166654d6174683a206469766973696f6e206279207a65726f60301b815250612890565b6000826123fd57506000610737565b8282028284828161240a57fe5b04146107345760405162461bcd60e51b815260040161053490613816565b6001600160a01b03821661244e5760405162461bcd60e51b8152600401610534906137c0565b61245781611aef565b156124745760405162461bcd60e51b815260040161053490613436565b612480600083836125b2565b6001600160a01b03821660009081526001602052604090206124a290826125d4565b506124af600282846125e0565b5060405181906001600160a01b03841690600090600080516020613cfd833981519152908290a45050565b6124e382611aef565b6124ff5760405162461bcd60e51b8152600401610534906138a3565b600082815260086020908152604090912082516106c492840190612c19565b612529600b826128c7565b6040516001600160a01b038216907f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b90600090a250565b61256b600b826118d7565b6040516001600160a01b038216907f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2490600090a250565b6000610734838361290f565b5490565b6125bb81610b3d565b6106c4576106c4816111d4565b60006107348383612927565b600061073483836129ed565b6000611dda84846001600160a01b038516612a37565b815460009082106126195760405162461bcd60e51b815260040161053490613307565b82600001828154811061262857fe5b9060005260206000200154905092915050565b8154600090819083106126605760405162461bcd60e51b815260040161053490613759565b600084600001848154811061267157fe5b906000526020600020906002020190508060000154816001015492509250509250929050565b600081848411156126bb5760405162461bcd60e51b81526004016105349190613283565b505050900390565b6060612718826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612ace9092919063ffffffff16565b8051909150156106c457808060200190518101906127369190612ea5565b6106c45760405162461bcd60e51b815260040161053490613b63565b600082815260018401602052604081205482816127825760405162461bcd60e51b81526004016105349190613283565b5084600001600182038154811061279557fe5b9060005260206000209060020201600101549150509392505050565b60006127c5846001600160a01b0316612add565b6127d157506001611bf6565b6060612859630a85bd0160e11b6127e6611afc565b8887876040516024016127fc94939291906131e0565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050604051806060016040528060328152602001613c82603291396001600160a01b0388169190612ace565b90506000818060200190518101906128719190612edd565b6001600160e01b031916630a85bd0160e11b1492505050949350505050565b600081836128b15760405162461bcd60e51b81526004016105349190613283565b5060008385816128bd57fe5b0495945050505050565b6128d18282611de4565b6128ed5760405162461bcd60e51b815260040161053490613718565b6001600160a01b0316600090815260209190915260409020805460ff19169055565b60009081526001919091016020526040902054151590565b600081815260018301602052604081205480156129e3578354600019808301919081019060009087908390811061295a57fe5b906000526020600020015490508087600001848154811061297757fe5b6000918252602080832090910192909255828152600189810190925260409020908401905586548790806129a757fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050610737565b6000915050610737565b60006129f9838361290f565b612a2f57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610737565b506000610737565b600082815260018401602052604081205480612a9c575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055611ddd565b82856000016001830381548110612aaf57fe5b9060005260206000209060020201600101819055506000915050611ddd565b6060611dda8484600085612ae3565b3b151590565b606082471015612b055760405162461bcd60e51b8152600401610534906135e4565b612b0e85612add565b612b2a5760405162461bcd60e51b815260040161053490613b2c565b60006060866001600160a01b03168587604051612b4791906130f6565b60006040518083038185875af1925050503d8060008114612b84576040519150601f19603f3d011682016040523d82523d6000602084013e612b89565b606091505b5091509150612b99828286612ba4565b979650505050505050565b60608315612bb3575081611ddd565b825115612bc35782518084602001fd5b8160405162461bcd60e51b81526004016105349190613283565b6040805160e081018252606080825260006020830181905292820183905281018290526080810182905260a0810182905260c081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612c5a57805160ff1916838001178555612c87565b82800160010185558215612c87579182015b82811115612c87578251825591602001919060010190612c6c565b50612c93929150612c97565b5090565b5b80821115612c935760008155600101612c98565b803561073781613c48565b600082601f830112612cc7578081fd5b81356001600160401b0380821115612cdd578283fd5b604051601f8301601f191681016020018281118282101715612cfd578485fd5b604052828152925082848301602001861015612d1857600080fd5b8260208601602083013760006020848301015250505092915050565b600060208284031215612d45578081fd5b813561073481613c48565b600060208284031215612d61578081fd5b815161073481613c48565b60008060408385031215612d7e578081fd5b8235612d8981613c48565b91506020830135612d9981613c48565b809150509250929050565b600080600060608486031215612db8578081fd5b8335612dc381613c48565b92506020840135612dd381613c48565b929592945050506040919091013590565b60008060008060808587031215612df9578081fd5b8435612e0481613c48565b93506020850135612e1481613c48565b92506040850135915060608501356001600160401b03811115612e35578182fd5b612e4187828801612cb7565b91505092959194509250565b60008060408385031215612e5f578182fd5b8235612e6a81613c48565b91506020830135612d9981613c5d565b60008060408385031215612e8c578182fd5b8235612e9781613c48565b946020939093013593505050565b600060208284031215612eb6578081fd5b815161073481613c5d565b600060208284031215612ed2578081fd5b813561073481613c6b565b600060208284031215612eee578081fd5b815161073481613c6b565b600060208284031215612f0a578081fd5b81356001600160401b03811115612f1f578182fd5b611bf684828501612cb7565b600060208284031215612f3c578081fd5b5035919050565b600060208284031215612f54578081fd5b5051919050565b600080600060608486031215612f6f578081fd5b833592506020840135612dd381613c48565b600080600080600080600060e0888a031215612f9b578485fd5b8735965060208801356001600160401b03811115612fb7578586fd5b612fc38a828b01612cb7565b9650506040880135612fd481613c48565b94506060880135612fe481613c48565b93506080880135612ff481613c48565b9699959850939692959460a0840135945060c09093013592915050565b6000806000806000806000806000806101408b8d031215613030578384fd5b8a35995060208b013560ff81168114613047578485fd5b985060408b0135975060608b0135965060808b01356001600160401b0381111561306f578485fd5b61307b8d828e01612cb7565b96505061308b8c60a08d01612cac565b945061309a8c60c08d01612cac565b93506130a98c60e08d01612cac565b92506101008b013591506101208b013590509295989b9194979a5092959850565b600081518084526130e2816020860160208601613c1c565b601f01601f19169290920160200192915050565b60008251613108818460208701613c1c565b9190910192915050565b6000808454600180821660008114613131576001811461314857613177565b60ff198316865260028304607f1686019350613177565b600283048886526020808720875b8381101561316f5781548a820152908501908201613156565b505050860193505b505050835161318a818360208801613c1c565b01949350505050565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b8152601c810191909152603c0190565b90815260200190565b6001600160a01b0391909116815260200190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613213908301846130ca565b9695505050505050565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b901515815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60006020825261073460208301846130ca565b600060e082526132a960e083018a6130ca565b6001600160a01b039889166020840152968816604083015250938616606085015291909416608083015260a082019390935260c00191909152919050565b60208082526006908201526565786973747360d01b604082015260600190565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252601f908201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6020808252600490820152632162757960e01b604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252601c908201527b115490cdcc8c4e881d1bdad95b88185b1c9958591e481b5a5b9d195960221b604082015260600190565b6020808252601b908201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604082015260600190565b6020808252600690820152651cdd185ad95960d21b604082015260600190565b60208082526008908201526710b7bbb732b927b360c11b604082015260600190565b60208082526024908201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526019908201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b604082015260600190565b6020808252600790820152662165786973747360c81b604082015260600190565b6020808252600890820152670857d85c9d1a5cdd60c21b604082015260600190565b6020808252600890820152670857d85b5bdd5b9d60c21b604082015260600190565b6020808252600b908201526a085c9959da5cdd195c995960aa1b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252602c908201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b60208082526038908201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776040820152771b995c881b9bdc88185c1c1c9bdd995908199bdc88185b1b60421b606082015260800190565b6020808252602a908201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604082015269726f206164647265737360b01b606082015260800190565b60208082526021908201527f526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c6040820152606560f81b606082015260800190565b60208082526022908201527f456e756d657261626c654d61703a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252600b908201526a0857de599b105b5bdd5b9d60aa1b604082015260600190565b6020808252818101527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604082015260600190565b60208082526007908201526610b9b4b3b732b960c91b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252602c908201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b6020808252602c908201527f4552433732314d657461646174613a2055524920736574206f66206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b6020808252600e908201526d10b7b934b3b4b730b6213abcb2b960911b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526022908201527f526f6c65733a206163636f756e7420697320746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526029908201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960408201526839903737ba1037bbb760b91b606082015260800190565b6020808252602f908201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60408201526e3732bc34b9ba32b73a103a37b5b2b760891b606082015260800190565b60208082526021908201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656040820152603960f91b606082015260800190565b60208082526030908201527f5369676e6572526f6c653a2063616c6c657220646f6573206e6f74206861766560408201526f20746865205369676e657220726f6c6560801b606082015260800190565b6020808252600a90820152691c9959da5cdd195c995960b21b604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600890820152671a5cd19d5b99195960c21b604082015260600190565b600088825260e06020830152613be860e08301896130ca565b6001600160a01b03978816604084015295871660608301525092909416608083015260a082015260c0019190915292915050565b60005b83811015613c37578181015183820152602001613c1f565b838111156109dc5750506000910152565b6001600160a01b03811681146107e257600080fd5b80151581146107e257600080fd5b6001600160e01b0319811681146107e257600080fdfe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212208ca701f5b44075cb1fd495e108ec1262de1a0215d99b379008bc42c3c88a506b64736f6c634300060c0033000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e000000000000000000000000000000000000000000000000000000000000000659464c4172740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000459464c4100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002268747470733a2f2f676174657761792e70696e6174612e636c6f75642f697066732f000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101ac5760003560e01c806301ffc9a7146101b1578063041dc891146101da57806305dca80e146101ef57806306fdde0314610204578063081812fc14610219578063095ea7b31461023957806318160ddd1461024c57806323b872dd146102545780632f745c591461026757806334a354ce1461027a57806342842e0e146102825780634903b0d1146102955780634f6ccce7146102a857806355f804b3146102bb5780635893253c146102ce5780635beac899146102f45780636352211e146103075780636c0360eb1461031a57806370a0823114610322578063715018a6146103355780637df73e271461033d5780638da5cb5b146103505780638f8e42f61461035857806395d89b411461036b578063a22cb46514610373578063a694fc3a14610386578063b88d4fde14610399578063bfa883ab146103ac578063c2c6c677146103bf578063c87b56dd146103d2578063ca1d209d146103e5578063d96a094a146103f8578063e5c8b03d1461040b578063e985e9c514610413578063eb12d61e14610426578063f2fde38b14610439575b600080fd5b6101c46101bf366004612ec1565b61044c565b6040516101d1919061325a565b60405180910390f35b6101e261046f565b6040516101d191906131c3565b6102026101fd366004613011565b610475565b005b61020c610558565b6040516101d19190613283565b61022c610227366004612f2b565b6105ee565b6040516101d191906131cc565b610202610247366004612e7a565b610631565b6101e26106c9565b610202610262366004612da4565b6106da565b6101e2610275366004612e7a565b610712565b61022c61073d565b610202610290366004612da4565b610761565b6101e26102a3366004612f2b565b61077c565b6101e26102b6366004612f2b565b61078e565b6102026102c9366004612ef9565b6107a4565b6102e16102dc366004612f2b565b6107e5565b6040516101d19796959493929190613296565b610202610302366004612f5b565b6108bb565b61022c610315366004612f2b565b6109e2565b61020c610a0a565b6101e2610330366004612d34565b610a6b565b610202610ab4565b6101c461034b366004612d34565b610b21565b61022c610b2e565b6101c4610366366004612f2b565b610b3d565b61020c610b5f565b610202610381366004612e4d565b610bc0565b610202610394366004612f2b565b610c8e565b6102026103a7366004612de4565b610dc0565b6102026103ba366004612da4565b610df9565b6102026103cd366004612f81565b61103d565b61020c6103e0366004612f2b565b61108a565b6102026103f3366004612f2b565b6111d4565b610202610406366004612f2b565b6112fe565b6102026117c2565b6101c4610421366004612d6c565b6117d4565b610202610434366004612d34565b611802565b610202610447366004612d34565b611832565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b600c5481565b61051860018b60405160200161048b91906131c3565b604051602081830303815290604052805190602001206040516020016104b19190613193565b604051602081830303815290604052805190602001208b8b8b604051600081526020016040526040516104e79493929190613265565b6020604051602081039080840390855afa158015610509573d6000803e3d6000fd5b50505060206040510351610b21565b61053d5760405162461bcd60e51b8152600401610534906137f5565b60405180910390fd5b61054c8a878787878787611923565b50505050505050505050565b60068054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105e45780601f106105b9576101008083540402835291602001916105e4565b820191906000526020600020905b8154815290600101906020018083116105c757829003601f168201915b5050505050905090565b60006105f982611aef565b6106155760405162461bcd60e51b815260040161053490613857565b506000908152600460205260409020546001600160a01b031690565b600061063c826109e2565b9050806001600160a01b0316836001600160a01b031614156106705760405162461bcd60e51b815260040161053490613a26565b806001600160a01b0316610682611afc565b6001600160a01b0316148061069e575061069e81610421611afc565b6106ba5760405162461bcd60e51b815260040161053490613676565b6106c48383611b00565b505050565b60006106d56002611b6e565b905090565b6106eb6106e5611afc565b82611b79565b6107075760405162461bcd60e51b815260040161053490613adb565b6106c4838383611bfe565b6001600160a01b03821660009081526001602052604081206107349083611cfa565b90505b92915050565b7f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e81565b6106c483838360405180602001604052806000815250610dc0565b600e6020526000908152604090205481565b60008061079c600284611d06565b509392505050565b6107ac611afc565b600a546001600160a01b039081169116146107d95760405162461bcd60e51b815260040161053490613917565b6107e281611d22565b50565b600d6020908152600091825260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845290929183919083018282801561087c5780601f106108515761010080835404028352916020019161087c565b820191906000526020600020905b81548152906001019060200180831161085f57829003601f168201915b505050506001830154600284015460038501546004860154600587015460069097015495966001600160a01b0394851696938516955091841693169187565b6108c63330856106da565b6000838152600d60205260409020600381018054336001600160a01b0319918216179091556004820180549091166001600160a01b0385161790556005810182905560060154600c546109199082611d35565b600c81905550600e6000858152602001908152602001600020600090556109dc33827f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b15801561099457600080fd5b505afa1580156109a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cc9190612d50565b6001600160a01b03169190611d77565b50505050565b600061073782604051806060016040528060298152602001613cb46029913960029190611dcd565b60098054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105e45780601f106105b9576101008083540402835291602001916105e4565b60006001600160a01b038216610a935760405162461bcd60e51b8152600401610534906136ce565b6001600160a01b038216600090815260016020526040902061073790611b6e565b610abc611afc565b600a546001600160a01b03908116911614610ae95760405162461bcd60e51b815260040161053490613917565b600a546040516000916001600160a01b031690600080516020613cdd833981519152908390a3600a80546001600160a01b0319169055565b6000610737600b83611de4565b600a546001600160a01b031690565b6000908152600e6020908152604080832054600d909252909120600601541490565b60078054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105e45780601f106105b9576101008083540402835291602001916105e4565b610bc8611afc565b6001600160a01b0316826001600160a01b03161415610bf95760405162461bcd60e51b815260040161053490613527565b8060056000610c06611afc565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155610c4a611afc565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610c82919061325a565b60405180910390a35050565b610c97816109e2565b6001600160a01b0316336001600160a01b031614610cc75760405162461bcd60e51b8152600401610534906134c1565b6000818152600e602052604090205480610cf35760405162461bcd60e51b8152600401610534906134a1565b6000828152600e6020526040812055600c54610d0f9082611d35565b600c556000610d1d82611e2c565b60405163a9059cbb60e01b81529091506001600160a01b037f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e169063a9059cbb90610d6e903390859060040161321d565b602060405180830381600087803b158015610d8857600080fd5b505af1158015610d9c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109dc9190612ea5565b610dd1610dcb611afc565b83611b79565b610ded5760405162461bcd60e51b815260040161053490613adb565b6109dc8484848461225c565b610e01611afc565b600a546001600160a01b03908116911614610e2e5760405162461bcd60e51b815260040161053490613917565b7f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b158015610e8757600080fd5b505afa158015610e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebf9190612d50565b6001600160a01b0316836001600160a01b0316141561100f57610ff0600c547f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190612d50565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610f9a91906131cc565b60206040518083038186803b158015610fb257600080fd5b505afa158015610fc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fea9190612f43565b90611d35565b81111561100f5760405162461bcd60e51b81526004016105349061359d565b60405163a9059cbb60e01b81526001600160a01b0384169063a9059cbb90610d6e908590859060040161321d565b611045611afc565b600a546001600160a01b039081169116146110725760405162461bcd60e51b815260040161053490613917565b61108187878787878787611923565b50505050505050565b606061109582611aef565b6110b15760405162461bcd60e51b8152600401610534906139d7565b60008281526008602090815260409182902080548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156111465780601f1061111b57610100808354040283529160200191611146565b820191906000526020600020905b81548152906001019060200180831161112957829003601f168201915b50506009549394505050506002600019610100600184161502019091160461116f57905061046a565b8051156111a15760098160405160200161118a929190613112565b60405160208183030381529060405291505061046a565b60096111ac8461228f565b6040516020016111bd929190613112565b604051602081830303815290604052915050919050565b6111dd81611aef565b6111f95760405162461bcd60e51b81526004016105349061355a565b61120281610b3d565b1561121f5760405162461bcd60e51b815260040161053490613bad565b6000818152600d6020908152604080832060060154600e909252909120819055600c5461124c9082612369565b600c819055506112fa3330837f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b1580156112b157600080fd5b505afa1580156112c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e99190612d50565b6001600160a01b031692919061238e565b5050565b611306612bdd565b6000828152600d602090815260409182902082518154600260018216156101009081026000190190921604601f81018590049094028201810190945260e081018381529093919284928491908401828280156113a35780601f10611378576101008083540402835291602001916113a3565b820191906000526020600020905b81548152906001019060200180831161138657829003601f168201915b505050918352505060018201546001600160a01b0390811660208301526002830154811660408301526003830154811660608301526004830154166080820152600582015460a082015260069091015460c09182015281015190915061141b5760405162461bcd60e51b8152600401610534906135bf565b61147e33308360c001517f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b1580156112b157600080fd5b6114a633308360a0015184608001516001600160a01b031661238e909392919063ffffffff16565b60c0810180516000848152600e602052604090205551600c546114c891612369565b600c556114d482611aef565b6116505760208101516001600160a01b0316156115205780602001516001600160a01b0316336001600160a01b0316146115205760405162461bcd60e51b8152600401610534906138ef565b6000611545605061153f60648560a001516123af90919063ffffffff16565b906123ee565b90506000611560828460a00151611d3590919063ffffffff16565b905061160b7f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b03166361d027b36040518163ffffffff1660e01b815260040160206040518083038186803b1580156115be57600080fd5b505afa1580156115d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f69190612d50565b60808501516001600160a01b03169084611d77565b61163183604001518285608001516001600160a01b0316611d779092919063ffffffff16565b61163b3385612428565b6116498484600001516124da565b50506112fa565b3061165a836109e2565b6001600160a01b0316146116805760405162461bcd60e51b8152600401610534906133d2565b600061169f605a61153f60648560a001516123af90919063ffffffff16565b905060006116ba828460a00151611d3590919063ffffffff16565b90506116c78160026123af565b606084015160808501519192506116e8916001600160a01b03169084611d77565b6117917f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b03166361d027b36040518163ffffffff1660e01b815260040160206040518083038186803b15801561174457600080fd5b505afa158015611758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177c9190612d50565b60808501516001600160a01b03169083611d77565b6117b783604001518285608001516001600160a01b0316611d779092919063ffffffff16565b6109dc303386611bfe565b6117d26117cd611afc565b61251e565b565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61180d61034b611afc565b6118295760405162461bcd60e51b815260040161053490613a67565b6107e281612560565b61183a611afc565b600a546001600160a01b039081169116146118675760405162461bcd60e51b815260040161053490613917565b6001600160a01b03811661188d5760405162461bcd60e51b8152600401610534906133f0565b600a546040516001600160a01b03808416921690600080516020613cdd83398151915290600090a3600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6118e18282611de4565b156118fe5760405162461bcd60e51b815260040161053490613349565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b61192c87611aef565b156119495760405162461bcd60e51b8152600401610534906132e7565b6000878152600d6020526040902060060154156119785760405162461bcd60e51b815260040161053490613ab7565b600081116119985760405162461bcd60e51b81526004016105349061379b565b6001600160a01b0384166119be5760405162461bcd60e51b81526004016105349061357b565b6040805160e0810182528781526001600160a01b0380881660208084019190915287821683850152600060608401819052918716608084015260a0830186905260c083018590528a8252600d81529290208151805192939192611a249284920190612c19565b5060208201516001820180546001600160a01b03199081166001600160a01b03938416179091556040808501516002850180548416918516919091179055606085015160038501805484169185169190911790556080850151600485018054909316931692909217905560a0830151600583015560c090920151600690910155517f676c6ca8bd2bf6f3412482eaa1dc0592fa9a9dd8f822574666177e537aafa19e90611ade908990899089908990899089908990613bcf565b60405180910390a150505050505050565b60006107376002836125a2565b3390565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611b35826109e2565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000610737826125ae565b6000611b8482611aef565b611ba05760405162461bcd60e51b81526004016105349061362a565b6000611bab836109e2565b9050806001600160a01b0316846001600160a01b03161480611be65750836001600160a01b0316611bdb846105ee565b6001600160a01b0316145b80611bf65750611bf681856117d4565b949350505050565b826001600160a01b0316611c11826109e2565b6001600160a01b031614611c375760405162461bcd60e51b81526004016105349061398e565b6001600160a01b038216611c5d5760405162461bcd60e51b8152600401610534906134e3565b611c688383836125b2565b611c73600082611b00565b6001600160a01b0383166000908152600160205260409020611c9590826125c8565b506001600160a01b0382166000908152600160205260409020611cb890826125d4565b50611cc5600282846125e0565b5080826001600160a01b0316846001600160a01b0316600080516020613cfd83398151915260405160405180910390a4505050565b600061073483836125f6565b6000808080611d15868661263b565b9097909650945050505050565b80516112fa906009906020840190612c19565b600061073483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612697565b6106c48363a9059cbb60e01b8484604051602401611d9692919061321d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526126c3565b6000611dda848484612752565b90505b9392505050565b60006001600160a01b038216611e0c5760405162461bcd60e51b81526004016105349061394c565b506001600160a01b03166000908152602091909152604090205460ff1690565b60007f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b158015611e8757600080fd5b505afa158015611e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebf9190612d50565b6001600160a01b031663095ea7b37f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e60006040518363ffffffff1660e01b8152600401611f0d92919061321d565b602060405180830381600087803b158015611f2757600080fd5b505af1158015611f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5f9190612ea5565b507f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e6001600160a01b031663a4803b336040518163ffffffff1660e01b815260040160206040518083038186803b158015611fb957600080fd5b505afa158015611fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ff19190612d50565b6001600160a01b031663095ea7b37f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e846040518363ffffffff1660e01b815260040161203e92919061321d565b602060405180830381600087803b15801561205857600080fd5b505af115801561206c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120909190612ea5565b506040516370a0823160e01b81526000906001600160a01b037f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e16906370a08231906120e09030906004016131cc565b60206040518083038186803b1580156120f857600080fd5b505afa15801561210c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121309190612f43565b60405163534a7e1d60e11b81529091506001600160a01b037f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e169063a694fc3a9061217f9086906004016131c3565b600060405180830381600087803b15801561219957600080fd5b505af11580156121ad573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b037f00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e1691506370a08231906122009030906004016131cc565b60206040518083038186803b15801561221857600080fd5b505afa15801561222c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122509190612f43565b9050611bf68183611d35565b612267848484611bfe565b612273848484846127b1565b6109dc5760405162461bcd60e51b815260040161053490613380565b6060816122b457506040805180820190915260018152600360fc1b602082015261046a565b8160005b81156122cc57600101600a820491506122b8565b6060816001600160401b03811180156122e457600080fd5b506040519080825280601f01601f19166020018201604052801561230f576020820181803683370190505b50859350905060001982015b831561236057600a840660300160f81b8282806001900393508151811061233e57fe5b60200101906001600160f81b031916908160001a905350600a8404935061231b565b50949350505050565b6000828201838110156107345760405162461bcd60e51b81526004016105349061346c565b6109dc846323b872dd60e01b858585604051602401611d9693929190613236565b600061073483836040518060400160405280601a815260200179536166654d6174683a206469766973696f6e206279207a65726f60301b815250612890565b6000826123fd57506000610737565b8282028284828161240a57fe5b04146107345760405162461bcd60e51b815260040161053490613816565b6001600160a01b03821661244e5760405162461bcd60e51b8152600401610534906137c0565b61245781611aef565b156124745760405162461bcd60e51b815260040161053490613436565b612480600083836125b2565b6001600160a01b03821660009081526001602052604090206124a290826125d4565b506124af600282846125e0565b5060405181906001600160a01b03841690600090600080516020613cfd833981519152908290a45050565b6124e382611aef565b6124ff5760405162461bcd60e51b8152600401610534906138a3565b600082815260086020908152604090912082516106c492840190612c19565b612529600b826128c7565b6040516001600160a01b038216907f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b90600090a250565b61256b600b826118d7565b6040516001600160a01b038216907f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2490600090a250565b6000610734838361290f565b5490565b6125bb81610b3d565b6106c4576106c4816111d4565b60006107348383612927565b600061073483836129ed565b6000611dda84846001600160a01b038516612a37565b815460009082106126195760405162461bcd60e51b815260040161053490613307565b82600001828154811061262857fe5b9060005260206000200154905092915050565b8154600090819083106126605760405162461bcd60e51b815260040161053490613759565b600084600001848154811061267157fe5b906000526020600020906002020190508060000154816001015492509250509250929050565b600081848411156126bb5760405162461bcd60e51b81526004016105349190613283565b505050900390565b6060612718826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612ace9092919063ffffffff16565b8051909150156106c457808060200190518101906127369190612ea5565b6106c45760405162461bcd60e51b815260040161053490613b63565b600082815260018401602052604081205482816127825760405162461bcd60e51b81526004016105349190613283565b5084600001600182038154811061279557fe5b9060005260206000209060020201600101549150509392505050565b60006127c5846001600160a01b0316612add565b6127d157506001611bf6565b6060612859630a85bd0160e11b6127e6611afc565b8887876040516024016127fc94939291906131e0565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050604051806060016040528060328152602001613c82603291396001600160a01b0388169190612ace565b90506000818060200190518101906128719190612edd565b6001600160e01b031916630a85bd0160e11b1492505050949350505050565b600081836128b15760405162461bcd60e51b81526004016105349190613283565b5060008385816128bd57fe5b0495945050505050565b6128d18282611de4565b6128ed5760405162461bcd60e51b815260040161053490613718565b6001600160a01b0316600090815260209190915260409020805460ff19169055565b60009081526001919091016020526040902054151590565b600081815260018301602052604081205480156129e3578354600019808301919081019060009087908390811061295a57fe5b906000526020600020015490508087600001848154811061297757fe5b6000918252602080832090910192909255828152600189810190925260409020908401905586548790806129a757fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050610737565b6000915050610737565b60006129f9838361290f565b612a2f57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610737565b506000610737565b600082815260018401602052604081205480612a9c575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055611ddd565b82856000016001830381548110612aaf57fe5b9060005260206000209060020201600101819055506000915050611ddd565b6060611dda8484600085612ae3565b3b151590565b606082471015612b055760405162461bcd60e51b8152600401610534906135e4565b612b0e85612add565b612b2a5760405162461bcd60e51b815260040161053490613b2c565b60006060866001600160a01b03168587604051612b4791906130f6565b60006040518083038185875af1925050503d8060008114612b84576040519150601f19603f3d011682016040523d82523d6000602084013e612b89565b606091505b5091509150612b99828286612ba4565b979650505050505050565b60608315612bb3575081611ddd565b825115612bc35782518084602001fd5b8160405162461bcd60e51b81526004016105349190613283565b6040805160e081018252606080825260006020830181905292820183905281018290526080810182905260a0810182905260c081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612c5a57805160ff1916838001178555612c87565b82800160010185558215612c87579182015b82811115612c87578251825591602001919060010190612c6c565b50612c93929150612c97565b5090565b5b80821115612c935760008155600101612c98565b803561073781613c48565b600082601f830112612cc7578081fd5b81356001600160401b0380821115612cdd578283fd5b604051601f8301601f191681016020018281118282101715612cfd578485fd5b604052828152925082848301602001861015612d1857600080fd5b8260208601602083013760006020848301015250505092915050565b600060208284031215612d45578081fd5b813561073481613c48565b600060208284031215612d61578081fd5b815161073481613c48565b60008060408385031215612d7e578081fd5b8235612d8981613c48565b91506020830135612d9981613c48565b809150509250929050565b600080600060608486031215612db8578081fd5b8335612dc381613c48565b92506020840135612dd381613c48565b929592945050506040919091013590565b60008060008060808587031215612df9578081fd5b8435612e0481613c48565b93506020850135612e1481613c48565b92506040850135915060608501356001600160401b03811115612e35578182fd5b612e4187828801612cb7565b91505092959194509250565b60008060408385031215612e5f578182fd5b8235612e6a81613c48565b91506020830135612d9981613c5d565b60008060408385031215612e8c578182fd5b8235612e9781613c48565b946020939093013593505050565b600060208284031215612eb6578081fd5b815161073481613c5d565b600060208284031215612ed2578081fd5b813561073481613c6b565b600060208284031215612eee578081fd5b815161073481613c6b565b600060208284031215612f0a578081fd5b81356001600160401b03811115612f1f578182fd5b611bf684828501612cb7565b600060208284031215612f3c578081fd5b5035919050565b600060208284031215612f54578081fd5b5051919050565b600080600060608486031215612f6f578081fd5b833592506020840135612dd381613c48565b600080600080600080600060e0888a031215612f9b578485fd5b8735965060208801356001600160401b03811115612fb7578586fd5b612fc38a828b01612cb7565b9650506040880135612fd481613c48565b94506060880135612fe481613c48565b93506080880135612ff481613c48565b9699959850939692959460a0840135945060c09093013592915050565b6000806000806000806000806000806101408b8d031215613030578384fd5b8a35995060208b013560ff81168114613047578485fd5b985060408b0135975060608b0135965060808b01356001600160401b0381111561306f578485fd5b61307b8d828e01612cb7565b96505061308b8c60a08d01612cac565b945061309a8c60c08d01612cac565b93506130a98c60e08d01612cac565b92506101008b013591506101208b013590509295989b9194979a5092959850565b600081518084526130e2816020860160208601613c1c565b601f01601f19169290920160200192915050565b60008251613108818460208701613c1c565b9190910192915050565b6000808454600180821660008114613131576001811461314857613177565b60ff198316865260028304607f1686019350613177565b600283048886526020808720875b8381101561316f5781548a820152908501908201613156565b505050860193505b505050835161318a818360208801613c1c565b01949350505050565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b8152601c810191909152603c0190565b90815260200190565b6001600160a01b0391909116815260200190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613213908301846130ca565b9695505050505050565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b901515815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60006020825261073460208301846130ca565b600060e082526132a960e083018a6130ca565b6001600160a01b039889166020840152968816604083015250938616606085015291909416608083015260a082019390935260c00191909152919050565b60208082526006908201526565786973747360d01b604082015260600190565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252601f908201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6020808252600490820152632162757960e01b604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252601c908201527b115490cdcc8c4e881d1bdad95b88185b1c9958591e481b5a5b9d195960221b604082015260600190565b6020808252601b908201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604082015260600190565b6020808252600690820152651cdd185ad95960d21b604082015260600190565b60208082526008908201526710b7bbb732b927b360c11b604082015260600190565b60208082526024908201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526019908201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b604082015260600190565b6020808252600790820152662165786973747360c81b604082015260600190565b6020808252600890820152670857d85c9d1a5cdd60c21b604082015260600190565b6020808252600890820152670857d85b5bdd5b9d60c21b604082015260600190565b6020808252600b908201526a085c9959da5cdd195c995960aa1b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252602c908201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b60208082526038908201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776040820152771b995c881b9bdc88185c1c1c9bdd995908199bdc88185b1b60421b606082015260800190565b6020808252602a908201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604082015269726f206164647265737360b01b606082015260800190565b60208082526021908201527f526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c6040820152606560f81b606082015260800190565b60208082526022908201527f456e756d657261626c654d61703a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252600b908201526a0857de599b105b5bdd5b9d60aa1b604082015260600190565b6020808252818101527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604082015260600190565b60208082526007908201526610b9b4b3b732b960c91b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252602c908201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b6020808252602c908201527f4552433732314d657461646174613a2055524920736574206f66206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b6020808252600e908201526d10b7b934b3b4b730b6213abcb2b960911b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526022908201527f526f6c65733a206163636f756e7420697320746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526029908201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960408201526839903737ba1037bbb760b91b606082015260800190565b6020808252602f908201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60408201526e3732bc34b9ba32b73a103a37b5b2b760891b606082015260800190565b60208082526021908201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656040820152603960f91b606082015260800190565b60208082526030908201527f5369676e6572526f6c653a2063616c6c657220646f6573206e6f74206861766560408201526f20746865205369676e657220726f6c6560801b606082015260800190565b6020808252600a90820152691c9959da5cdd195c995960b21b604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600890820152671a5cd19d5b99195960c21b604082015260600190565b600088825260e06020830152613be860e08301896130ca565b6001600160a01b03978816604084015295871660608301525092909416608083015260a082015260c0019190915292915050565b60005b83811015613c37578181015183820152602001613c1f565b838111156109dc5750506000910152565b6001600160a01b03811681146107e257600080fd5b80151581146107e257600080fd5b6001600160e01b0319811681146107e257600080fdfe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212208ca701f5b44075cb1fd495e108ec1262de1a0215d99b379008bc42c3c88a506b64736f6c634300060c0033

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

000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e000000000000000000000000000000000000000000000000000000000000000659464c4172740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000459464c4100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002268747470733a2f2f676174657761792e70696e6174612e636c6f75642f697066732f000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): YFLArt
Arg [1] : _symbol (string): YFLA
Arg [2] : _baseURI (string): https://gateway.pinata.cloud/ipfs/
Arg [3] : _yYFL (address): 0x75D1aA733920b14fC74c9F6e6faB7ac1EcE8482E

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [3] : 00000000000000000000000075d1aa733920b14fc74c9f6e6fab7ac1ece8482e
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [5] : 59464c4172740000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [7] : 59464c4100000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000022
Arg [9] : 68747470733a2f2f676174657761792e70696e6174612e636c6f75642f697066
Arg [10] : 732f000000000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

76553:9698:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9981:142;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;76700:24;;;:::i;:::-;;;;;;;:::i;78398:580::-;;;;;;:::i;:::-;;:::i;:::-;;46457:92;;;:::i;:::-;;;;;;;:::i;49144:213::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;48688:390::-;;;;;;:::i;:::-;;:::i;48182:203::-;;;:::i;50018:305::-;;;;;;:::i;:::-;;:::i;47952:154::-;;;;;;:::i;:::-;;:::i;76668:27::-;;;:::i;50394:151::-;;;;;;:::i;:::-;;:::i;77023:43::-;;;;;;:::i;:::-;;:::i;48462:164::-;;;;;;:::i;:::-;;:::i;80577:99::-;;;;;;:::i;:::-;;:::i;76932:44::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;;:::i;83131:511::-;;;;;;:::i;:::-;;:::i;46221:169::-;;;;;;:::i;:::-;;:::i;47779:89::-;;;:::i;45944:215::-;;;;;;:::i;:::-;;:::i;67246:148::-;;;:::i;69300:109::-;;;;;;:::i;:::-;;:::i;66604:79::-;;;:::i;84352:133::-;;;;;;:::i;:::-;;:::i;46618:96::-;;;:::i;49429:295::-;;;;;;:::i;:::-;;:::i;82519:343::-;;;;;;:::i;:::-;;:::i;50616:285::-;;;;;;:::i;:::-;;:::i;79310:297::-;;;;;;:::i;:::-;;:::i;80093:354::-;;;;;;:::i;:::-;;:::i;46785:755::-;;;;;;:::i;:::-;;:::i;83851:331::-;;;;;;:::i;:::-;;:::i;80866:1499::-;;;;;;:::i;:::-;;:::i;69517:79::-;;;:::i;49795:156::-;;;;;;:::i;:::-;;:::i;69417:92::-;;;;;;:::i;:::-;;:::i;67549:244::-;;;;;;:::i;:::-;;:::i;9981:142::-;-1:-1:-1;;;;;;10082:33:0;;10058:4;10082:33;;;;;;;;;;;;;9981:142;;;;:::o;76700:24::-;;;;:::o;78398:580::-;78694:154;78703:144;78822:8;78805:26;;;;;;;;:::i;:::-;;;;;;;;;;;;;78795:37;;;;;;78733:100;;;;;;;;:::i;:::-;;;;;;;;;;;;;78723:111;;;;;;78836:2;78840;78844;78703:144;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;78694:8;:154::i;:::-;78686:181;;;;-1:-1:-1;;;78686:181:0;;;;;;;:::i;:::-;;;;;;;;;78874:98;78884:8;78894:9;78905:14;78921:7;78930:13;78945:14;78961:10;78874:9;:98::i;:::-;78398:580;;;;;;;;;;:::o;46457:92::-;46536:5;46529:12;;;;;;;;-1:-1:-1;;46529:12:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46503:13;;46529:12;;46536:5;;46529:12;;46536:5;46529:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46457:92;:::o;49144:213::-;49212:7;49240:16;49248:7;49240;:16::i;:::-;49232:73;;;;-1:-1:-1;;;49232:73:0;;;;;;;:::i;:::-;-1:-1:-1;49325:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;49325:24:0;;49144:213::o;48688:390::-;48769:13;48785:16;48793:7;48785;:16::i;:::-;48769:32;;48826:5;-1:-1:-1;;;;;48820:11:0;:2;-1:-1:-1;;;;;48820:11:0;;;48812:57;;;;-1:-1:-1;;;48812:57:0;;;;;;;:::i;:::-;48906:5;-1:-1:-1;;;;;48890:21:0;:12;:10;:12::i;:::-;-1:-1:-1;;;;;48890:21:0;;:62;;;;48915:37;48932:5;48939:12;:10;:12::i;48915:37::-;48882:154;;;;-1:-1:-1;;;48882:154:0;;;;;;;:::i;:::-;49049:21;49058:2;49062:7;49049:8;:21::i;:::-;48688:390;;;:::o;48182:203::-;48235:7;48356:21;:12;:19;:21::i;:::-;48349:28;;48182:203;:::o;50018:305::-;50179:41;50198:12;:10;:12::i;:::-;50212:7;50179:18;:41::i;:::-;50171:103;;;;-1:-1:-1;;;50171:103:0;;;;;;;:::i;:::-;50287:28;50297:4;50303:2;50307:7;50287:9;:28::i;47952:154::-;-1:-1:-1;;;;;48068:20:0;;48041:7;48068:20;;;:13;:20;;;;;:30;;48092:5;48068:23;:30::i;:::-;48061:37;;47952:154;;;;;:::o;76668:27::-;;;:::o;50394:151::-;50498:39;50515:4;50521:2;50525:7;50498:39;;;;;;;;;;;;:16;:39::i;77023:43::-;;;;;;;;;;;;;:::o;48462:164::-;48529:7;;48571:22;:12;48587:5;48571:15;:22::i;:::-;-1:-1:-1;48549:44:0;48462:164;-1:-1:-1;;;48462:164:0:o;80577:99::-;66826:12;:10;:12::i;:::-;66816:6;;-1:-1:-1;;;;;66816:6:0;;;:22;;;66808:67;;;;-1:-1:-1;;;66808:67:0;;;;;;;:::i;:::-;80649:21:::1;80661:8;80649:11;:21::i;:::-;80577:99:::0;:::o;76932:44::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;76932:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;76932:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;76932:44:0;;;;;;;;-1:-1:-1;76932:44:0;;;;;;;:::o;83131:511::-;83256:49;83269:10;83289:4;83296:8;83256:12;:49::i;:::-;83312:18;;;;:8;:18;;;;;:27;;;:40;;83342:10;-1:-1:-1;;;;;;83312:40:0;;;;;;;83359:31;;;:47;;;;;-1:-1:-1;;;;;83359:47:0;;;;;83413:32;;;:49;;;83486:28;;;83533:9;;:21;;83486:28;83533:13;:21::i;:::-;83521:9;:33;;;;83568:8;:18;83577:8;83568:18;;;;;;;;;;;83561:25;;;83593:43;83617:10;83629:6;83593:4;-1:-1:-1;;;;;83593:8:0;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;83593:23:0;;:43;:23;:43::i;:::-;83131:511;;;;:::o;46221:169::-;46285:7;46312:70;46329:7;46312:70;;;;;;;;;;;;;;;;;:12;;:70;:16;:70::i;47779:89::-;47852:8;47845:15;;;;;;;;-1:-1:-1;;47845:15:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47819:13;;47845:15;;47852:8;;47845:15;;47852:8;47845:15;;;;;;;;;;;;;;;;;;;;;;;;45944:215;46008:7;-1:-1:-1;;;;;46036:19:0;;46028:74;;;;-1:-1:-1;;;46028:74:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;46122:20:0;;;;;;:13;:20;;;;;:29;;:27;:29::i;67246:148::-;66826:12;:10;:12::i;:::-;66816:6;;-1:-1:-1;;;;;66816:6:0;;;:22;;;66808:67;;;;-1:-1:-1;;;66808:67:0;;;;;;;:::i;:::-;67337:6:::1;::::0;67316:40:::1;::::0;67353:1:::1;::::0;-1:-1:-1;;;;;67337:6:0::1;::::0;-1:-1:-1;;;;;;;;;;;67316:40:0;67353:1;;67316:40:::1;67367:6;:19:::0;;-1:-1:-1;;;;;;67367:19:0::1;::::0;;67246:148::o;69300:109::-;69356:4;69380:21;:8;69393:7;69380:12;:21::i;66604:79::-;66669:6;;-1:-1:-1;;;;;66669:6:0;66604:79;:::o;84352:133::-;84409:4;84461:18;;;:8;:18;;;;;;;;;84429:8;:18;;;;;;:28;;;:50;;84352:133::o;46618:96::-;46699:7;46692:14;;;;;;;;-1:-1:-1;;46692:14:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46666:13;;46692:14;;46699:7;;46692:14;;46699:7;46692:14;;;;;;;;;;;;;;;;;;;;;;;;49429:295;49544:12;:10;:12::i;:::-;-1:-1:-1;;;;;49532:24:0;:8;-1:-1:-1;;;;;49532:24:0;;;49524:62;;;;-1:-1:-1;;;49524:62:0;;;;;;;:::i;:::-;49644:8;49599:18;:32;49618:12;:10;:12::i;:::-;-1:-1:-1;;;;;49599:32:0;;;;;;;;;;;;;;;;;-1:-1:-1;49599:32:0;;;:42;;;;;;;;;;;;:53;;-1:-1:-1;;49599:53:0;;;;;;;;;;;49683:12;:10;:12::i;:::-;-1:-1:-1;;;;;49668:48:0;;49707:8;49668:48;;;;;;:::i;:::-;;;;;;;;49429:295;;:::o;82519:343::-;82590:17;82598:8;82590:7;:17::i;:::-;-1:-1:-1;;;;;82576:31:0;:10;-1:-1:-1;;;;;82576:31:0;;82568:52;;;;-1:-1:-1;;;82568:52:0;;;;;;;:::i;:::-;82627:14;82644:18;;;:8;:18;;;;;;82677:10;82669:29;;;;-1:-1:-1;;;82669:29:0;;;;;;;:::i;:::-;82712:18;;;;:8;:18;;;;;82705:25;82749:9;;:21;;82763:6;82749:13;:21::i;:::-;82737:9;:33;82777:14;82794;82801:6;82794;:14::i;:::-;82815:41;;-1:-1:-1;;;82815:41:0;;82777:31;;-1:-1:-1;;;;;;82822:4:0;82815:21;;;;:41;;82837:10;;82777:31;;82815:41;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;50616:285::-;50748:41;50767:12;:10;:12::i;:::-;50781:7;50748:18;:41::i;:::-;50740:103;;;;-1:-1:-1;;;50740:103:0;;;;;;;:::i;:::-;50854:39;50868:4;50874:2;50878:7;50887:5;50854:13;:39::i;79310:297::-;66826:12;:10;:12::i;:::-;66816:6;;-1:-1:-1;;;;;66816:6:0;;;:22;;;66808:67;;;;-1:-1:-1;;;66808:67:0;;;;;;;:::i;:::-;79448:4:::1;-1:-1:-1::0;;;;;79448:8:0::1;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;79421:38:0::1;79429:6;-1:-1:-1::0;;;;;79421:38:0::1;;79417:143;;;79489:50;79529:9;;79489:4;-1:-1:-1::0;;;;;79489:8:0::1;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;79489:20:0::1;;79518:4;79489:35;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:39:::0;::::1;:50::i;:::-;79478:7;:61;;79470:82;;;;-1:-1:-1::0;;;79470:82:0::1;;;;;;;:::i;:::-;79566:35;::::0;-1:-1:-1;;;79566:35:0;;-1:-1:-1;;;;;79566:15:0;::::1;::::0;::::1;::::0;:35:::1;::::0;79582:9;;79593:7;;79566:35:::1;;;:::i;80093:354::-:0;66826:12;:10;:12::i;:::-;66816:6;;-1:-1:-1;;;;;66816:6:0;;;:22;;;66808:67;;;;-1:-1:-1;;;66808:67:0;;;;;;;:::i;:::-;80343:98:::1;80353:8;80363:9;80374:14;80390:7;80399:13;80414:14;80430:10;80343:9;:98::i;:::-;80093:354:::0;;;;;;;:::o;46785:755::-;46850:13;46884:16;46892:7;46884;:16::i;:::-;46876:76;;;;-1:-1:-1;;;46876:76:0;;;;;;;:::i;:::-;46991:19;;;;:10;:19;;;;;;;;;46965:45;;;;;;-1:-1:-1;;46965:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:23;;:45;;;46991:19;46965:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;47092:8:0;47086:22;46965:45;;-1:-1:-1;;;;47086:22:0;-1:-1:-1;;47086:22:0;;;;;;;;;;;47082:76;;47137:9;-1:-1:-1;47130:16:0;;47082:76;47262:23;;:27;47258:112;;47337:8;47347:9;47320:37;;;;;;;;;:::i;:::-;;;;;;;;;;;;;47306:52;;;;;47258:112;47502:8;47512:18;:7;:16;:18::i;:::-;47485:46;;;;;;;;;:::i;:::-;;;;;;;;;;;;;47471:61;;;46785:755;;;:::o;83851:331::-;83905:17;83913:8;83905:7;:17::i;:::-;83897:37;;;;-1:-1:-1;;;83897:37:0;;;;;;;:::i;:::-;83950:18;83959:8;83950;:18::i;:::-;83949:19;83941:40;;;;-1:-1:-1;;;83941:40:0;;;;;;;:::i;:::-;83988:14;84005:18;;;:8;:18;;;;;;;;:28;;;84040:8;:18;;;;;;:27;;;84086:9;;:21;;84005:28;84086:13;:21::i;:::-;84074:9;:33;;;;84114:62;84142:10;84162:4;84169:6;84114:4;-1:-1:-1;;;;;84114:8:0;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;84114:27:0;;:62;;:27;:62::i;:::-;83851:331;;:::o;80866:1499::-;80931:21;;:::i;:::-;80955:18;;;;:8;:18;;;;;;;;;80931:42;;;;;;;;;;;;;-1:-1:-1;;80931:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80955:18;;80931:42;;80955:18;;80931:42;;;80955:18;80931:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;80931:42:0;;;-1:-1:-1;;80931:42:0;;;;-1:-1:-1;;;;;80931:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80988:15;;;80931:42;;-1:-1:-1;80980:43:0;;;;-1:-1:-1;;;80980:43:0;;;;;;;:::i;:::-;81030:71;81058:10;81078:4;81085:5;:15;;;81030:4;-1:-1:-1;;;;;81030:8:0;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:71;81108:91;81152:10;81172:4;81179:5;:19;;;81115:5;:18;;;-1:-1:-1;;;;;81108:43:0;;;:91;;;;;;:::i;:::-;81227:15;;;;;81206:18;;;;:8;:18;;;;;:36;81275:15;81261:9;;:30;;:13;:30::i;:::-;81249:9;:42;81303:17;81311:8;81303:7;:17::i;:::-;81298:1062;;81335:19;;;;-1:-1:-1;;;;;81335:33:0;;81331:120;;81403:5;:19;;;-1:-1:-1;;;;;81389:33:0;:10;-1:-1:-1;;;;;81389:33:0;;81381:60;;;;-1:-1:-1;;;81381:60:0;;;;;;;:::i;:::-;81459:18;81480:36;81513:2;81480:28;81504:3;81480:5;:19;;;:23;;:28;;;;:::i;:::-;:32;;:36::i;:::-;81459:57;;81525:17;81545:35;81569:10;81545:5;:19;;;:23;;:35;;;;:::i;:::-;81525:55;;81589:68;81629:4;-1:-1:-1;;;;;81629:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81596:18;;;;-1:-1:-1;;;;;81589:39:0;;81646:10;81589:39;:68::i;:::-;81666:64;81706:5;:12;;;81720:9;81673:5;:18;;;-1:-1:-1;;;;;81666:39:0;;;:64;;;;;:::i;:::-;81739:27;81745:10;81757:8;81739:5;:27::i;:::-;81775:38;81788:8;81798:5;:14;;;81775:12;:38::i;:::-;81298:1062;;;;;81873:4;81844:17;81852:8;81844:7;:17::i;:::-;-1:-1:-1;;;;;81844:34:0;;81836:51;;;;-1:-1:-1;;;81836:51:0;;;;;;;:::i;:::-;81896:19;81918:36;81951:2;81918:28;81942:3;81918:5;:19;;;:23;;:28;;;;:::i;:36::-;81896:58;;81963:20;81986:36;82010:11;81986:5;:19;;;:23;;:36;;;;:::i;:::-;81963:59;-1:-1:-1;82046:19:0;81963:59;82063:1;82046:16;:19::i;:::-;82114:14;;;;82081:18;;;;82031:34;;-1:-1:-1;82074:68:0;;-1:-1:-1;;;;;82074:39:0;;82130:11;82074:39;:68::i;:::-;82151:70;82191:4;-1:-1:-1;;;;;82191:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;82158:18;;;;-1:-1:-1;;;;;82151:39:0;;82208:12;82151:39;:70::i;:::-;82230:67;82270:5;:12;;;82284;82237:5;:18;;;-1:-1:-1;;;;;82230:39:0;;;:67;;;;;:::i;:::-;82306:46;82324:4;82331:10;82343:8;82306:9;:46::i;69517:79::-;69561:27;69575:12;:10;:12::i;:::-;69561:13;:27::i;:::-;69517:79::o;49795:156::-;-1:-1:-1;;;;;49908:25:0;;;49884:4;49908:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;49795:156::o;69417:92::-;69197:22;69206:12;:10;:12::i;69197:22::-;69189:83;;;;-1:-1:-1;;;69189:83:0;;;;;;;:::i;:::-;69482:19:::1;69493:7;69482:10;:19::i;67549:244::-:0;66826:12;:10;:12::i;:::-;66816:6;;-1:-1:-1;;;;;66816:6:0;;;:22;;;66808:67;;;;-1:-1:-1;;;66808:67:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;67638:22:0;::::1;67630:73;;;;-1:-1:-1::0;;;67630:73:0::1;;;;;;;:::i;:::-;67740:6;::::0;67719:38:::1;::::0;-1:-1:-1;;;;;67719:38:0;;::::1;::::0;67740:6:::1;::::0;-1:-1:-1;;;;;;;;;;;67719:38:0;67740:6:::1;::::0;67719:38:::1;67768:6;:17:::0;;-1:-1:-1;;;;;;67768:17:0::1;-1:-1:-1::0;;;;;67768:17:0;;;::::1;::::0;;;::::1;::::0;;67549:244::o;68083:178::-;68161:18;68165:4;68171:7;68161:3;:18::i;:::-;68160:19;68152:63;;;;-1:-1:-1;;;68152:63:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;68226:20:0;:11;:20;;;;;;;;;;;:27;;-1:-1:-1;;68226:27:0;68249:4;68226:27;;;68083:178::o;84936:869::-;85179:17;85187:8;85179:7;:17::i;:::-;85178:18;85170:37;;;;-1:-1:-1;;;85170:37:0;;;;;;;:::i;:::-;85222:18;;;;:8;:18;;;;;:28;;;:33;85214:56;;;;-1:-1:-1;;;85214:56:0;;;;;;;:::i;:::-;85298:1;85285:10;:14;85277:38;;;;-1:-1:-1;;;85277:38:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;85330:21:0;;85322:42;;;;-1:-1:-1;;;85322:42:0;;;;;;;:::i;:::-;85392:240;;;;;;;;;;;-1:-1:-1;;;;;85392:240:0;;;;;;;;;;;;;;;;;;-1:-1:-1;85392:240:0;;;;;;;;;;;;;;;;;;;;;;;;;85371:18;;;:8;:18;;;;;:261;;;;85392:240;;85371:18;;:261;;:18;;:261;;;:::i;:::-;-1:-1:-1;85371:261:0;;;;;;;;;-1:-1:-1;;;;;;85371:261:0;;;-1:-1:-1;;;;;85371:261:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85644:155;;;;;85663:8;;85680:9;;85698:14;;85721:7;;85737:13;;85759:14;;85782:10;;85644:155;:::i;:::-;;;;;;;;84936:869;;;;;;;:::o;52368:119::-;52425:4;52449:30;:12;52471:7;52449:21;:30::i;657:106::-;745:10;657:106;:::o;58195:158::-;58261:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;58261:29:0;-1:-1:-1;;;;;58261:29:0;;;;;;;;:24;;58315:16;58261:24;58315:7;:16::i;:::-;-1:-1:-1;;;;;58306:39:0;;;;;;;;;;;58195:158;;:::o;39945:123::-;40014:7;40041:19;40049:3;40041:7;:19::i;52654:333::-;52739:4;52764:16;52772:7;52764;:16::i;:::-;52756:73;;;;-1:-1:-1;;;52756:73:0;;;;;;;:::i;:::-;52840:13;52856:16;52864:7;52856;:16::i;:::-;52840:32;;52902:5;-1:-1:-1;;;;;52891:16:0;:7;-1:-1:-1;;;;;52891:16:0;;:51;;;;52935:7;-1:-1:-1;;;;;52911:31:0;:20;52923:7;52911:11;:20::i;:::-;-1:-1:-1;;;;;52911:31:0;;52891:51;:87;;;;52946:32;52963:5;52970:7;52946:16;:32::i;:::-;52883:96;52654:333;-1:-1:-1;;;;52654:333:0:o;55743:574::-;55861:4;-1:-1:-1;;;;;55841:24:0;:16;55849:7;55841;:16::i;:::-;-1:-1:-1;;;;;55841:24:0;;55833:78;;;;-1:-1:-1;;;55833:78:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;55930:16:0;;55922:65;;;;-1:-1:-1;;;55922:65:0;;;;;;;:::i;:::-;56000:39;56021:4;56027:2;56031:7;56000:20;:39::i;:::-;56104:29;56121:1;56125:7;56104:8;:29::i;:::-;-1:-1:-1;;;;;56146:19:0;;;;;;:13;:19;;;;;:35;;56173:7;56146:26;:35::i;:::-;-1:-1:-1;;;;;;56192:17:0;;;;;;:13;:17;;;;;:30;;56214:7;56192:21;:30::i;:::-;-1:-1:-1;56235:29:0;:12;56252:7;56261:2;56235:16;:29::i;:::-;;56301:7;56297:2;-1:-1:-1;;;;;56282:27:0;56291:4;-1:-1:-1;;;;;56282:27:0;-1:-1:-1;;;;;;;;;;;56282:27:0;;;;;;;;;55743:574;;;:::o;32579:137::-;32650:7;32685:22;32689:3;32701:5;32685:3;:22::i;40407:227::-;40487:7;;;;40547:22;40551:3;40563:5;40547:3;:22::i;:::-;40516:53;;;;-1:-1:-1;40407:227:0;-1:-1:-1;;;;;40407:227:0:o;56918:100::-;56991:19;;;;:8;;:19;;;;;:::i;12096:136::-;12154:7;12181:43;12185:1;12188;12181:43;;;;;;;;;;;;;;;;;:3;:43::i;62459:177::-;62542:86;62562:5;62592:23;;;62617:2;62621:5;62569:58;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;62569:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;62569:58:0;-1:-1:-1;;;;;;62569:58:0;;;;;;;;;;62542:19;:86::i;41069:204::-;41176:7;41219:44;41224:3;41244;41250:12;41219:4;:44::i;:::-;41211:53;-1:-1:-1;41069:204:0;;;;;;:::o;68619:203::-;68691:4;-1:-1:-1;;;;;68716:21:0;;68708:68;;;;-1:-1:-1;;;68708:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;;68794:20:0;:11;:20;;;;;;;;;;;;;;;68619:203::o;85895:353::-;85946:14;85969:4;-1:-1:-1;;;;;85969:8:0;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;85969:18:0;;85996:4;86003:1;85969:36;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;86012:4;-1:-1:-1;;;;;86012:8:0;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;86012:18:0;;86039:4;86046:7;86012:42;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;86084:29:0;;-1:-1:-1;;;86084:29:0;;86061:20;;-1:-1:-1;;;;;86084:4:0;:14;;;;:29;;86107:4;;86084:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;86120:19;;-1:-1:-1;;;86120:19:0;;86061:52;;-1:-1:-1;;;;;;86120:4:0;:10;;;;:19;;86131:7;;86120:19;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;86168:29:0;;-1:-1:-1;;;86168:29:0;;86146:19;;-1:-1:-1;;;;;;86168:4:0;:14;;-1:-1:-1;86168:14:0;;:29;;86191:4;;86168:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;86146:51;-1:-1:-1;86213:29:0;86146:51;86229:12;86213:15;:29::i;51783:272::-;51897:28;51907:4;51913:2;51917:7;51897:9;:28::i;:::-;51944:48;51967:4;51973:2;51977:7;51986:5;51944:22;:48::i;:::-;51936:111;;;;-1:-1:-1;;;51936:111:0;;;;;;;:::i;41485:744::-;41541:13;41762:10;41758:53;;-1:-1:-1;41789:10:0;;;;;;;;;;;;-1:-1:-1;;;41789:10:0;;;;;;41758:53;41836:5;41821:12;41877:78;41884:9;;41877:78;;41910:8;;41941:2;41933:10;;;;41877:78;;;41965:19;41997:6;-1:-1:-1;;;;;41987:17:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;41987:17:0;-1:-1:-1;42059:5:0;;-1:-1:-1;41965:39:0;-1:-1:-1;;;42031:10:0;;42075:115;42082:9;;42075:115;;42149:2;42142:4;:9;42137:2;:14;42126:27;;42108:6;42115:7;;;;;;;42108:15;;;;;;;;;;;:45;-1:-1:-1;;;;;42108:45:0;;;;;;;;-1:-1:-1;42176:2:0;42168:10;;;;42075:115;;;-1:-1:-1;42214:6:0;41485:744;-1:-1:-1;;;;41485:744:0:o;11632:181::-;11690:7;11722:5;;;11746:6;;;;11738:46;;;;-1:-1:-1;;;11738:46:0;;;;;;;:::i;62644:205::-;62745:96;62765:5;62795:27;;;62824:4;62830:2;62834:5;62772:68;;;;;;;;;;:::i;13933:132::-;13991:7;14018:39;14022:1;14025;14018:39;;;;;;;;;;;;;-1:-1:-1;;;14018:39:0;;;:3;:39::i;12986:471::-;13044:7;13289:6;13285:47;;-1:-1:-1;13319:1:0;13312:8;;13285:47;13356:5;;;13360:1;13356;:5;:1;13380:5;;;;;:10;13372:56;;;;-1:-1:-1;;;13372:56:0;;;;;;;:::i;54253:404::-;-1:-1:-1;;;;;54333:16:0;;54325:61;;;;-1:-1:-1;;;54325:61:0;;;;;;;:::i;:::-;54406:16;54414:7;54406;:16::i;:::-;54405:17;54397:58;;;;-1:-1:-1;;;54397:58:0;;;;;;;:::i;:::-;54468:45;54497:1;54501:2;54505:7;54468:20;:45::i;:::-;-1:-1:-1;;;;;54526:17:0;;;;;;:13;:17;;;;;:30;;54548:7;54526:21;:30::i;:::-;-1:-1:-1;54569:29:0;:12;54586:7;54595:2;54569:16;:29::i;:::-;-1:-1:-1;54616:33:0;;54641:7;;-1:-1:-1;;;;;54616:33:0;;;54633:1;;-1:-1:-1;;;;;;;;;;;54616:33:0;54633:1;;54616:33;54253:404;;:::o;56473:215::-;56573:16;56581:7;56573;:16::i;:::-;56565:73;;;;-1:-1:-1;;;56565:73:0;;;;;;;:::i;:::-;56649:19;;;;:10;:19;;;;;;;;:31;;;;;;;;:::i;69734:130::-;69794:24;:8;69810:7;69794:15;:24::i;:::-;69834:22;;-1:-1:-1;;;;;69834:22:0;;;;;;;;69734:130;:::o;69604:122::-;69661:21;:8;69674:7;69661:12;:21::i;:::-;69698:20;;-1:-1:-1;;;;;69698:20:0;;;;;;;;69604:122;:::o;39706:151::-;39790:4;39814:35;39824:3;39844;39814:9;:35::i;37328:110::-;37411:19;;37328:110::o;84682:195::-;84821:18;84830:8;84821;:18::i;:::-;84816:56;;84850:14;84855:8;84850:4;:14::i;31666:137::-;31736:4;31760:35;31768:3;31788:5;31760:7;:35::i;31359:131::-;31426:4;31450:32;31455:3;31475:5;31450:4;:32::i;39138:176::-;39227:4;39251:55;39256:3;39276;-1:-1:-1;;;;;39290:14:0;;39251:4;:55::i;27653:204::-;27748:18;;27720:7;;27748:26;-1:-1:-1;27740:73:0;;;;-1:-1:-1;;;27740:73:0;;;;;;;:::i;:::-;27831:3;:11;;27843:5;27831:18;;;;;;;;;;;;;;;;27824:25;;27653:204;;;;:::o;37793:279::-;37897:19;;37860:7;;;;37897:27;-1:-1:-1;37889:74:0;;;;-1:-1:-1;;;37889:74:0;;;;;;;:::i;:::-;37976:22;38001:3;:12;;38014:5;38001:19;;;;;;;;;;;;;;;;;;37976:44;;38039:5;:10;;;38051:5;:12;;;38031:33;;;;;37793:279;;;;;:::o;12535:192::-;12621:7;12657:12;12649:6;;;;12641:29;;;;-1:-1:-1;;;12641:29:0;;;;;;;;:::i;:::-;-1:-1:-1;;;12693:5:0;;;12535:192::o;64764:761::-;65188:23;65214:69;65242:4;65214:69;;;;;;;;;;;;;;;;;65222:5;-1:-1:-1;;;;;65214:27:0;;;:69;;;;;:::i;:::-;65298:17;;65188:95;;-1:-1:-1;65298:21:0;65294:224;;65440:10;65429:30;;;;;;;;;;;;:::i;:::-;65421:85;;;;-1:-1:-1;;;65421:85:0;;;;;;;:::i;38495:319::-;38589:7;38628:17;;;:12;;;:17;;;;;;38679:12;38664:13;38656:36;;;;-1:-1:-1;;;38656:36:0;;;;;;;;:::i;:::-;;38746:3;:12;;38770:1;38759:8;:12;38746:26;;;;;;;;;;;;;;;;;;:33;;;38739:40;;;38495:319;;;;;:::o;57583:604::-;57704:4;57731:15;:2;-1:-1:-1;;;;;57731:13:0;;:15::i;:::-;57726:60;;-1:-1:-1;57770:4:0;57763:11;;57726:60;57796:23;57822:252;-1:-1:-1;;;57935:12:0;:10;:12::i;:::-;57962:4;57981:7;58003:5;57838:181;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;;;;;57838:181:0;;;;;;;-1:-1:-1;;;;;57838:181:0;;;;;;;;;;;57822:252;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;57822:15:0;;;:252;:15;:252::i;:::-;57796:278;;58085:13;58112:10;58101:32;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;;58152:26:0;-1:-1:-1;;;58152:26:0;;-1:-1:-1;;;57583:604:0;;;;;;:::o;14561:278::-;14647:7;14682:12;14675:5;14667:28;;;;-1:-1:-1;;;14667:28:0;;;;;;;;:::i;:::-;;14706:9;14722:1;14718;:5;;;;;;;14561:278;-1:-1:-1;;;;;14561:278:0:o;68341:183::-;68421:18;68425:4;68431:7;68421:3;:18::i;:::-;68413:64;;;;-1:-1:-1;;;68413:64:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;68488:20:0;68511:5;68488:20;;;;;;;;;;;:28;;-1:-1:-1;;68488:28:0;;;68341:183::o;37108:125::-;37179:4;37203:17;;;:12;;;;;:17;;;;;;:22;;;37108:125::o;25355:1544::-;25421:4;25560:19;;;:12;;;:19;;;;;;25596:15;;25592:1300;;26031:18;;-1:-1:-1;;25982:14:0;;;;26031:22;;;;25958:21;;26031:3;;:22;;26318;;;;;;;;;;;;;;26298:42;;26464:9;26435:3;:11;;26447:13;26435:26;;;;;;;;;;;;;;;;;;;:38;;;;26541:23;;;26583:1;26541:12;;;:23;;;;;;26567:17;;;26541:43;;26693:17;;26541:3;;26693:17;;;;;;;;;;;;;;;;;;;;;;26788:3;:12;;:19;26801:5;26788:19;;;;;;;;;;;26781:26;;;26831:4;26824:11;;;;;;;;25592:1300;26875:5;26868:12;;;;;24765:414;24828:4;24850:21;24860:3;24865:5;24850:9;:21::i;:::-;24845:327;;-1:-1:-1;24888:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;25071:18;;25049:19;;;:12;;;:19;;;;;;:40;;;;25104:11;;24845:327;-1:-1:-1;25155:5:0;25148:12;;34608:692;34684:4;34819:17;;;:12;;;:17;;;;;;34853:13;34849:444;;-1:-1:-1;;34938:38:0;;;;;;;;;;;;;;;;;;34920:57;;;;;;;;:12;:57;;;;;;;;;;;;;;;;;;;;;;;;35135:19;;35115:17;;;:12;;;:17;;;;;;;:39;35169:11;;34849:444;35249:5;35213:3;:12;;35237:1;35226:8;:12;35213:26;;;;;;;;;;;;;;;;;;:33;;:41;;;;35276:5;35269:12;;;;;19745:195;19848:12;19880:52;19902:6;19910:4;19916:1;19919:12;19880:21;:52::i;16827:422::-;17194:20;17233:8;;;16827:422::o;20797:530::-;20924:12;20982:5;20957:21;:30;;20949:81;;;;-1:-1:-1;;;20949:81:0;;;;;;;:::i;:::-;21049:18;21060:6;21049:10;:18::i;:::-;21041:60;;;;-1:-1:-1;;;21041:60:0;;;;;;;:::i;:::-;21175:12;21189:23;21216:6;-1:-1:-1;;;;;21216:11:0;21236:5;21244:4;21216:33;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21174:75;;;;21267:52;21285:7;21294:10;21306:12;21267:17;:52::i;:::-;21260:59;20797:530;-1:-1:-1;;;;;;;20797:530:0:o;22333:742::-;22448:12;22477:7;22473:595;;;-1:-1:-1;22508:10:0;22501:17;;22473:595;22622:17;;:21;22618:439;;22885:10;22879:17;22946:15;22933:10;22929:2;22925:19;22918:44;22833:148;23028:12;23021:20;;-1:-1:-1;;;23021:20:0;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;5:130;72:20;;97:33;72:20;97:33;:::i;961:440::-;;1062:3;1055:4;1047:6;1043:17;1039:27;1029:2;;-1:-1;;1070:12;1029:2;1104:20;;-1:-1;;;;;54298:30;;;54295:2;;;-1:-1;;54331:12;54295:2;53965;53959:9;54404;54385:17;;-1:-1;;54381:33;53991:17;;54472:4;53991:17;54051:34;;;54087:22;;;54048:62;54045:2;;;-1:-1;;54113:12;54045:2;53965;54132:22;1209:21;;;1130:73;-1:-1;1130:73;1309:16;;;54472:4;1309:16;1306:25;-1:-1;1303:2;;;1344:1;;1334:12;1303:2;57698:6;54472:4;1251:6;1247:17;54472:4;1285:5;1281:16;57675:30;57754:1;54472:4;57745:6;1285:5;57736:16;;57729:27;;;;1022:379;;;;:::o;2609:241::-;;2713:2;2701:9;2692:7;2688:23;2684:32;2681:2;;;-1:-1;;2719:12;2681:2;85:6;72:20;97:33;124:5;97:33;:::i;2857:263::-;;2972:2;2960:9;2951:7;2947:23;2943:32;2940:2;;;-1:-1;;2978:12;2940:2;226:6;220:13;238:33;265:5;238:33;:::i;3127:366::-;;;3248:2;3236:9;3227:7;3223:23;3219:32;3216:2;;;-1:-1;;3254:12;3216:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;3306:63;-1:-1;3406:2;3445:22;;72:20;97:33;72:20;97:33;:::i;:::-;3414:63;;;;3210:283;;;;;:::o;3500:491::-;;;;3638:2;3626:9;3617:7;3613:23;3609:32;3606:2;;;-1:-1;;3644:12;3606:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;3696:63;-1:-1;3796:2;3835:22;;72:20;97:33;72:20;97:33;:::i;:::-;3600:391;;3804:63;;-1:-1;;;3904:2;3943:22;;;;2265:20;;3600:391::o;3998:721::-;;;;;4162:3;4150:9;4141:7;4137:23;4133:33;4130:2;;;-1:-1;;4169:12;4130:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;4221:63;-1:-1;4321:2;4360:22;;72:20;97:33;72:20;97:33;:::i;:::-;4329:63;-1:-1;4429:2;4468:22;;2265:20;;-1:-1;4565:2;4550:18;;4537:32;-1:-1;;;;;4578:30;;4575:2;;;-1:-1;;4611:12;4575:2;4641:62;4695:7;4686:6;4675:9;4671:22;4641:62;:::i;:::-;4631:72;;;4124:595;;;;;;;:::o;4726:360::-;;;4844:2;4832:9;4823:7;4819:23;4815:32;4812:2;;;-1:-1;;4850:12;4812:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;4902:63;-1:-1;5002:2;5038:22;;347:20;372:30;347:20;372:30;:::i;5093:366::-;;;5214:2;5202:9;5193:7;5189:23;5185:32;5182:2;;;-1:-1;;5220:12;5182:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;5272:63;5372:2;5411:22;;;;2265:20;;-1:-1;;;5176:283::o;5466:257::-;;5578:2;5566:9;5557:7;5553:23;5549:32;5546:2;;;-1:-1;;5584:12;5546:2;495:6;489:13;507:30;531:5;507:30;:::i;5730:239::-;;5833:2;5821:9;5812:7;5808:23;5804:32;5801:2;;;-1:-1;;5839:12;5801:2;765:6;752:20;777:32;803:5;777:32;:::i;5976:261::-;;6090:2;6078:9;6069:7;6065:23;6061:32;6058:2;;;-1:-1;;6096:12;6058:2;904:6;898:13;916:32;942:5;916:32;:::i;7072:347::-;;7186:2;7174:9;7165:7;7161:23;7157:32;7154:2;;;-1:-1;;7192:12;7154:2;7237:31;;-1:-1;;;;;7277:30;;7274:2;;;-1:-1;;7310:12;7274:2;7340:63;7395:7;7386:6;7375:9;7371:22;7340:63;:::i;7426:241::-;;7530:2;7518:9;7509:7;7505:23;7501:32;7498:2;;;-1:-1;;7536:12;7498:2;-1:-1;2265:20;;7492:175;-1:-1;7492:175::o;7674:263::-;;7789:2;7777:9;7768:7;7764:23;7760:32;7757:2;;;-1:-1;;7795:12;7757:2;-1:-1;2413:13;;7751:186;-1:-1;7751:186::o;7944:491::-;;;;8082:2;8070:9;8061:7;8057:23;8053:32;8050:2;;;-1:-1;;8088:12;8050:2;2278:6;2265:20;8140:63;;8240:2;8283:9;8279:22;72:20;97:33;124:5;97:33;:::i;8442:1101::-;;;;;;;;8658:3;8646:9;8637:7;8633:23;8629:33;8626:2;;;-1:-1;;8665:12;8626:2;2265:20;;;-1:-1;8845:2;8830:18;;8817:32;-1:-1;;;;;8858:30;;8855:2;;;-1:-1;;8891:12;8855:2;8921:63;8976:7;8967:6;8956:9;8952:22;8921:63;:::i;:::-;8911:73;;;9021:2;9064:9;9060:22;72:20;97:33;124:5;97:33;:::i;:::-;9029:63;-1:-1;9129:2;9168:22;;72:20;97:33;72:20;97:33;:::i;:::-;9137:63;-1:-1;9237:3;9277:22;;72:20;97:33;72:20;97:33;:::i;:::-;8620:923;;;;-1:-1;8620:923;;;;9246:63;9346:3;9386:22;;2265:20;;-1:-1;9455:3;9495:22;;;2265:20;;8620:923;-1:-1;;8620:923::o;9550:1475::-;;;;;;;;;;;9815:3;9803:9;9794:7;9790:23;9786:33;9783:2;;;-1:-1;;9822:12;9783:2;2278:6;2265:20;9874:63;;9974:2;10015:9;10011:22;2541:20;56812:4;59163:5;56801:16;59140:5;59137:33;59127:2;;-1:-1;;59174:12;59127:2;9982:61;-1:-1;10080:2;10119:22;;616:20;;-1:-1;10188:2;10227:22;;616:20;;-1:-1;10324:3;10309:19;;10296:33;-1:-1;;;;;10338:30;;10335:2;;;-1:-1;;10371:12;10335:2;10401:63;10456:7;10447:6;10436:9;10432:22;10401:63;:::i;:::-;10391:73;;;10520:53;10565:7;10501:3;10545:9;10541:22;10520:53;:::i;:::-;10510:63;;10629:53;10674:7;10610:3;10654:9;10650:22;10629:53;:::i;:::-;10619:63;;10738:53;10783:7;10719:3;10763:9;10759:22;10738:53;:::i;:::-;10728:63;;10828:3;10872:9;10868:22;2265:20;10837:63;;10937:3;10981:9;10977:22;2265:20;10946:63;;9777:1248;;;;;;;;;;;;;:::o;11835:343::-;;11977:5;55075:12;55360:6;55355:3;55348:19;12070:52;12115:6;55397:4;55392:3;55388:14;55397:4;12096:5;12092:16;12070:52;:::i;:::-;54404:9;58277:14;-1:-1;;58273:28;12134:39;;;;55397:4;12134:39;;11925:253;-1:-1;;11925:253::o;29521:271::-;;12345:5;55075:12;12456:52;12501:6;12496:3;12489:4;12482:5;12478:16;12456:52;:::i;:::-;12520:16;;;;;29655:137;-1:-1;;29655:137::o;29799:430::-;;-1:-1;13741:5;13735:12;13775:1;;13764:9;13760:17;13788:1;13783:268;;;;14062:1;14057:425;;;;13753:729;;13783:268;-1:-1;;13988:25;;13976:38;;13857:1;13842:17;;13861:4;13838:28;14028:16;;;-1:-1;13783:268;;14057:425;14126:1;14115:9;14111:17;54928:3;-1:-1;54918:14;54960:4;;-1:-1;54947:18;-1:-1;14315:130;14329:6;14326:1;14323:13;14315:130;;;14388:14;;14375:11;;;14368:35;14422:15;;;;14344:12;;14315:130;;;-1:-1;;;14459:16;;;-1:-1;13753:729;;;;12345:5;55075:12;12456:52;12501:6;12496:3;12489:4;12482:5;12478:16;12456:52;:::i;:::-;12520:16;;29980:249;-1:-1;;;;29980:249::o;30236:520::-;-1:-1;;;15807:87;;15791:2;15913:12;;11627:37;;;;30719:12;;;30453:303::o;30763:253::-;11627:37;;;30988:2;30979:12;;30879:137::o;31023:222::-;-1:-1;;;;;56596:54;;;;11268:45;;31150:2;31135:18;;31121:124::o;31252:672::-;-1:-1;;;;;56596:54;;;11268:45;;56596:54;;31678:2;31663:18;;11268:45;31761:2;31746:18;;11627:37;;;31497:3;31798:2;31783:18;;31776:48;;;31252:672;;31838:76;;31482:19;;31900:6;31838:76;:::i;:::-;31830:84;31468:456;-1:-1;;;;;;31468:456::o;31931:349::-;-1:-1;;;;;56596:54;;;;11111:58;;32266:2;32251:18;;11627:37;32094:2;32079:18;;32065:215::o;32287:444::-;-1:-1;;;;;56596:54;;;11268:45;;56596:54;;;;32634:2;32619:18;;11268:45;32717:2;32702:18;;11627:37;;;;32470:2;32455:18;;32441:290::o;33434:210::-;56165:13;;56158:21;11510:34;;33555:2;33540:18;;33526:118::o;33651:548::-;11627:37;;;56812:4;56801:16;;;;34019:2;34004:18;;29474:35;34102:2;34087:18;;11627:37;34185:2;34170:18;;11627:37;33858:3;33843:19;;33829:370::o;34463:310::-;;34610:2;34631:17;34624:47;34685:78;34610:2;34599:9;34595:18;34749:6;34685:78;:::i;34780:980::-;;35095:3;35117:17;35110:47;35171:78;35095:3;35084:9;35080:19;35235:6;35171:78;:::i;:::-;-1:-1;;;;;56596:54;;;35328:2;35313:18;;11268:45;56596:54;;;35411:2;35396:18;;11268:45;-1:-1;56596:54;;;35494:2;35479:18;;11268:45;56596:54;;;;35577:3;35562:19;;11268:45;56607:42;35646:19;;11627:37;;;;35745:3;35730:19;11627:37;;;;35163:86;35066:694;-1:-1;35066:694::o;35767:416::-;35967:2;35981:47;;;14721:1;35952:18;;;55348:19;-1:-1;;;55388:14;;;14736:29;14784:12;;;35938:245::o;36190:416::-;36390:2;36404:47;;;15035:2;36375:18;;;55348:19;15071:34;55388:14;;;15051:55;-1:-1;;;15126:12;;;15119:26;15164:12;;;36361:245::o;36613:416::-;36813:2;36827:47;;;15415:2;36798:18;;;55348:19;15451:33;55388:14;;;15431:54;15504:12;;;36784:245::o;37036:416::-;37236:2;37250:47;;;16164:2;37221:18;;;55348:19;16200:34;55388:14;;;16180:55;-1:-1;;;16255:12;;;16248:42;16309:12;;;37207:245::o;37459:416::-;37659:2;37673:47;;;16560:1;37644:18;;;55348:19;-1:-1;;;55388:14;;;16575:27;16621:12;;;37630:245::o;37882:416::-;38082:2;38096:47;;;16872:2;38067:18;;;55348:19;16908:34;55388:14;;;16888:55;-1:-1;;;16963:12;;;16956:30;17005:12;;;38053:245::o;38305:416::-;38505:2;38519:47;;;17256:2;38490:18;;;55348:19;-1:-1;;;55388:14;;;17272:51;17342:12;;;38476:245::o;38728:416::-;38928:2;38942:47;;;17593:2;38913:18;;;55348:19;-1:-1;;;55388:14;;;17609:50;17678:12;;;38899:245::o;39151:416::-;39351:2;39365:47;;;17929:1;39336:18;;;55348:19;-1:-1;;;55388:14;;;17944:29;17992:12;;;39322:245::o;39574:416::-;39774:2;39788:47;;;18243:1;39759:18;;;55348:19;-1:-1;;;55388:14;;;18258:31;18308:12;;;39745:245::o;39997:416::-;40197:2;40211:47;;;18559:2;40182:18;;;55348:19;18595:34;55388:14;;;18575:55;-1:-1;;;18650:12;;;18643:28;18690:12;;;40168:245::o;40420:416::-;40620:2;40634:47;;;18941:2;40605:18;;;55348:19;-1:-1;;;55388:14;;;18957:48;19024:12;;;40591:245::o;40843:416::-;41043:2;41057:47;;;19275:1;41028:18;;;55348:19;-1:-1;;;55388:14;;;19290:30;19339:12;;;41014:245::o;41266:416::-;41466:2;41480:47;;;19590:1;41451:18;;;55348:19;-1:-1;;;55388:14;;;19605:31;19655:12;;;41437:245::o;41689:416::-;41889:2;41903:47;;;19906:1;41874:18;;;55348:19;-1:-1;;;55388:14;;;19921:31;19971:12;;;41860:245::o;42112:416::-;42312:2;42326:47;;;20222:2;42297:18;;;55348:19;-1:-1;;;55388:14;;;20238:34;20291:12;;;42283:245::o;42535:416::-;42735:2;42749:47;;;20542:2;42720:18;;;55348:19;20578:34;55388:14;;;20558:55;-1:-1;;;20633:12;;;20626:30;20675:12;;;42706:245::o;42958:416::-;43158:2;43172:47;;;20926:2;43143:18;;;55348:19;20962:34;55388:14;;;20942:55;-1:-1;;;21017:12;;;21010:36;21065:12;;;43129:245::o;43381:416::-;43581:2;43595:47;;;21316:2;43566:18;;;55348:19;21352:34;55388:14;;;21332:55;-1:-1;;;21407:12;;;21400:48;21467:12;;;43552:245::o;43804:416::-;44004:2;44018:47;;;21718:2;43989:18;;;55348:19;21754:34;55388:14;;;21734:55;-1:-1;;;21809:12;;;21802:34;21855:12;;;43975:245::o;44227:416::-;44427:2;44441:47;;;22106:2;44412:18;;;55348:19;22142:34;55388:14;;;22122:55;-1:-1;;;22197:12;;;22190:25;22234:12;;;44398:245::o;44650:416::-;44850:2;44864:47;;;22485:2;44835:18;;;55348:19;22521:34;55388:14;;;22501:55;-1:-1;;;22576:12;;;22569:26;22614:12;;;44821:245::o;45073:416::-;45273:2;45287:47;;;22865:2;45258:18;;;55348:19;-1:-1;;;55388:14;;;22881:34;22934:12;;;45244:245::o;45496:416::-;45696:2;45710:47;;;45681:18;;;55348:19;23221:34;55388:14;;;23201:55;23275:12;;;45667:245::o;45919:416::-;46119:2;46133:47;;;23526:1;46104:18;;;55348:19;-1:-1;;;55388:14;;;23541:30;23590:12;;;46090:245::o;46342:416::-;46542:2;46556:47;;;23841:2;46527:18;;;55348:19;23877:34;55388:14;;;23857:55;-1:-1;;;23932:12;;;23925:25;23969:12;;;46513:245::o;46765:416::-;46965:2;46979:47;;;24220:2;46950:18;;;55348:19;24256:34;55388:14;;;24236:55;-1:-1;;;24311:12;;;24304:36;24359:12;;;46936:245::o;47188:416::-;47388:2;47402:47;;;24610:2;47373:18;;;55348:19;24646:34;55388:14;;;24626:55;-1:-1;;;24701:12;;;24694:36;24749:12;;;47359:245::o;47611:416::-;47811:2;47825:47;;;25000:2;47796:18;;;55348:19;-1:-1;;;55388:14;;;25016:37;25072:12;;;47782:245::o;48034:416::-;48234:2;48248:47;;;48219:18;;;55348:19;25359:34;55388:14;;;25339:55;25413:12;;;48205:245::o;48457:416::-;48657:2;48671:47;;;25664:2;48642:18;;;55348:19;25700:34;55388:14;;;25680:55;-1:-1;;;25755:12;;;25748:26;25793:12;;;48628:245::o;48880:416::-;49080:2;49094:47;;;26044:2;49065:18;;;55348:19;26080:34;55388:14;;;26060:55;-1:-1;;;26135:12;;;26128:33;26180:12;;;49051:245::o;49303:416::-;49503:2;49517:47;;;26431:2;49488:18;;;55348:19;26467:34;55388:14;;;26447:55;-1:-1;;;26522:12;;;26515:39;26573:12;;;49474:245::o;49726:416::-;49926:2;49940:47;;;26824:2;49911:18;;;55348:19;26860:34;55388:14;;;26840:55;-1:-1;;;26915:12;;;26908:25;26952:12;;;49897:245::o;50149:416::-;50349:2;50363:47;;;27203:2;50334:18;;;55348:19;27239:34;55388:14;;;27219:55;-1:-1;;;27294:12;;;27287:40;27346:12;;;50320:245::o;50572:416::-;50772:2;50786:47;;;27597:2;50757:18;;;55348:19;-1:-1;;;55388:14;;;27613:33;27665:12;;;50743:245::o;50995:416::-;51195:2;51209:47;;;27916:2;51180:18;;;55348:19;27952:34;55388:14;;;27932:55;-1:-1;;;28007:12;;;28000:41;28060:12;;;51166:245::o;51418:416::-;51618:2;51632:47;;;28311:2;51603:18;;;55348:19;28347:31;55388:14;;;28327:52;28398:12;;;51589:245::o;51841:416::-;52041:2;52055:47;;;28649:2;52026:18;;;55348:19;28685:34;55388:14;;;28665:55;-1:-1;;;28740:12;;;28733:34;28786:12;;;52012:245::o;52264:416::-;52464:2;52478:47;;;29037:1;52449:18;;;55348:19;-1:-1;;;55388:14;;;29052:31;29102:12;;;52435:245::o;52916:980::-;;11657:5;11634:3;11627:37;53231:3;53350:2;53339:9;53335:18;53328:48;53390:78;53231:3;53220:9;53216:19;53454:6;53390:78;:::i;:::-;-1:-1;;;;;56596:54;;;53547:2;53532:18;;11268:45;56596:54;;;53630:2;53615:18;;11268:45;-1:-1;56596:54;;;;53713:3;53698:19;;11268:45;56607:42;53782:19;;11627:37;53881:3;53866:19;11627:37;;;;53382:86;53202:694;-1:-1;;53202:694::o;57771:268::-;57836:1;57843:101;57857:6;57854:1;57851:13;57843:101;;;57924:11;;;57918:18;57905:11;;;57898:39;57879:2;57872:10;57843:101;;;57959:6;57956:1;57953:13;57950:2;;;-1:-1;;57836:1;58006:16;;57999:27;57820:219::o;58314:117::-;-1:-1;;;;;56596:54;;58373:35;;58363:2;;58422:1;;58412:12;58438:111;58519:5;56165:13;56158:21;58497:5;58494:32;58484:2;;58540:1;;58530:12;58680:115;-1:-1;;;;;;56331:78;;58738:34;;58728:2;;58786:1;;58776:12

Swarm Source

ipfs://8ca701f5b44075cb1fd495e108ec1262de1a0215d99b379008bc42c3c88a506b
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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