ETH Price: $3,346.10 (-1.00%)

Contract

0x753412F4FB7245BCF1c0714fDf59ba89110f39b8
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Approval For...214514102024-12-21 14:14:116 days ago1734790451IN
Liquid Key: ALKEY Token
0 ETH0.000240519.71731757
Set Approval For...206520572024-09-01 0:12:47118 days ago1725149567IN
Liquid Key: ALKEY Token
0 ETH0.000026941.08848515
Set Approval For...201221972024-06-19 0:24:23192 days ago1718756663IN
Liquid Key: ALKEY Token
0 ETH0.000210664.50770341
Set Approval For...200505792024-06-09 0:05:23202 days ago1717891523IN
Liquid Key: ALKEY Token
0 ETH0.000247625.29710834
Set Approval For...200329482024-06-06 13:00:47204 days ago1717678847IN
Liquid Key: ALKEY Token
0 ETH0.0004326917.48198014
Set Approval For...195212372024-03-26 21:22:23276 days ago1711488143IN
Liquid Key: ALKEY Token
0 ETH0.0009841839.76355564
Set Approval For...193586712024-03-04 1:59:35299 days ago1709517575IN
Liquid Key: ALKEY Token
0 ETH0.0011908147.94911185
Set Approval For...192491982024-02-17 17:55:59314 days ago1708192559IN
Liquid Key: ALKEY Token
0 ETH0.0004749319.12352922
Set Approval For...192491972024-02-17 17:55:47314 days ago1708192547IN
Liquid Key: ALKEY Token
0 ETH0.0004770619.27450505
Set Approval For...191440082024-02-02 23:33:59329 days ago1706916839IN
Liquid Key: ALKEY Token
0 ETH0.0004389317.73397913
Set Approval For...190773272024-01-24 15:15:35338 days ago1706109335IN
Liquid Key: ALKEY Token
0 ETH0.0004621318.60834931
Set Approval For...190573992024-01-21 19:52:59341 days ago1705866779IN
Liquid Key: ALKEY Token
0 ETH0.0004879119.71312816
Set Approval For...190573992024-01-21 19:52:59341 days ago1705866779IN
Liquid Key: ALKEY Token
0 ETH0.0004895719.71312816
Set Approval For...190573982024-01-21 19:52:35341 days ago1705866755IN
Liquid Key: ALKEY Token
0 ETH0.0004888719.68480152
Set Approval For...189802192024-01-11 0:48:35352 days ago1704934115IN
Liquid Key: ALKEY Token
0 ETH0.0011647147.05713655
Set Approval For...189650952024-01-08 21:55:11354 days ago1704750911IN
Liquid Key: ALKEY Token
0 ETH0.001104623.62952771
Set Approval For...188685992023-12-26 8:12:35367 days ago1703578355IN
Liquid Key: ALKEY Token
0 ETH0.0003319213.4106158
Set Approval For...188345252023-12-21 13:25:23372 days ago1703165123IN
Liquid Key: ALKEY Token
0 ETH0.0009403937.86586243
Set Approval For...188199742023-12-19 12:23:35374 days ago1702988615IN
Liquid Key: ALKEY Token
0 ETH0.0011949848.28031433
Set Approval For...188130642023-12-18 13:06:47375 days ago1702904807IN
Liquid Key: ALKEY Token
0 ETH0.0030037964.25640762
Safe Transfer Fr...185872422023-11-16 21:50:11407 days ago1700171411IN
Liquid Key: ALKEY Token
0 ETH0.0015755229.25921927
Set Approval For...185612822023-11-13 6:45:47410 days ago1699857947IN
Liquid Key: ALKEY Token
0 ETH0.0016895636.2077639
Safe Transfer Fr...184452392023-10-28 0:51:35427 days ago1698454295IN
Liquid Key: ALKEY Token
0 ETH0.0010485410.48162889
Set Approval For...183829362023-10-19 7:36:47435 days ago1697701007IN
Liquid Key: ALKEY Token
0 ETH0.000295786.33868586
Set Approval For...183483762023-10-14 11:38:47440 days ago1697283527IN
Liquid Key: ALKEY Token
0 ETH0.00013995.6334476
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LiquidKeys

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-08-04
*/

// SPDX-License-Identifier: MIT

/*
   .____    .__             .__    .___  ____  __.
   |    |   |__| ________ __|__| __| _/ |    |/ _|____ ___.__. ______
   |    |   |  |/ ____/  |  \  |/ __ |  |      <_/ __ <   |  |/  ___/
   |    |___|  < <_|  |  |  /  / /_/ |  |    |  \  ___/\___  |\___ \
   |_______ \__|\__   |____/|__\____ |  |____|__ \___  > ____/____  >
           \/      |__|             \/          \/   \/\/         \/
     _____                .____    .__             .__    .___   .__
    /  _  \ ______   ____ |    |   |__| ________ __|__| __| _/   |__| ____
   /  /_\  \\____ \_/ __ \|    |   |  |/ ____/  |  \  |/ __ |    |  |/  _ \
  /    |    \  |_> >  ___/|    |___|  < <_|  |  |  /  / /_/ |    |  (  <_> )
  \____|__  /   __/ \___  >_______ \__|\__   |____/|__\____ | /\ |__|\____/
          \/|__|        \/        \/      |__|             \/ \/

    ** Contract written by Aleph 0ne and using at least one NODE ********
*/
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(
        bytes32 indexed role,
        bytes32 indexed previousAdminRole,
        bytes32 indexed newAdminRole
    );

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(
        bytes32 indexed role,
        address indexed account,
        address indexed sender
    );

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(
        bytes32 indexed role,
        address indexed account,
        address indexed sender
    );

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account)
        external
        view
        returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

pragma solidity ^0.8.0;

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

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index)
        external
        view
        returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

pragma solidity ^0.8.0;

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

            if (lastIndex != toDeleteIndex) {
                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] = valueIndex; // Replace lastvalue's index to valueIndex
            }

            // 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)
    {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

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

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set)
        internal
        view
        returns (bytes32[] memory)
    {
        return _values(set._inner);
    }

    // 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(uint160(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(uint160(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(uint160(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(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set)
        internal
        view
        returns (address[] memory)
    {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        assembly {
            result := store
        }

        return result;
    }

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

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set)
        internal
        view
        returns (uint256[] memory)
    {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly {
            result := store
        }

        return result;
    }
}

pragma solidity ^0.8.0;

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

pragma solidity ^0.8.0;

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

pragma solidity ^0.8.0;

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

pragma solidity ^0.8.0;

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

pragma solidity ^0.8.0;

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

        (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");

        (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");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

pragma solidity ^0.8.0;

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

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

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal 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);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length)
        internal
        pure
        returns (string memory)
    {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

pragma solidity ^0.8.0;

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

pragma solidity ^0.8.0;

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // 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;

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

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

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

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId)
        public
        view
        virtual
        override
        returns (address)
    {
        address owner = _owners[tokenId];
        require(
            owner != address(0),
            "ERC721: owner query for nonexistent token"
        );
        return owner;
    }

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

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

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

        string memory baseURI = _baseURI();
        return
            bytes(baseURI).length > 0
                ? string(abi.encodePacked(baseURI, tokenId.toString()))
                : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.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
        virtual
        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
    {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator)
        public
        view
        virtual
        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 virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

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

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `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);

        _balances[to] += 1;
        _owners[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 = ERC721.ownerOf(tokenId);

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

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

        _balances[owner] -= 1;
        delete _owners[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(
            ERC721.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);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits a {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC721: approve to caller");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @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()) {
            try
                IERC721Receiver(to).onERC721Received(
                    _msgSender(),
                    from,
                    tokenId,
                    _data
                )
            returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert(
                        "ERC721: transfer to non ERC721Receiver implementer"
                    );
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @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` and `to` are never both zero.
     *
     * 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 {}
}

pragma solidity ^0.8.0;

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

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

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account)
        public
        view
        virtual
        override
        returns (bool)
    {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role)
        public
        view
        virtual
        override
        returns (bytes32)
    {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account)
        public
        virtual
        override
        onlyRole(getRoleAdmin(role))
    {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account)
        public
        virtual
        override
        onlyRole(getRoleAdmin(role))
    {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account)
        public
        virtual
        override
    {
        require(
            account == _msgSender(),
            "AccessControl: can only renounce roles for self"
        );

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

pragma solidity ^0.8.0;

/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
 * enumerability of all the token ids in the contract as well as all token ids owned by each
 * account.
 */
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

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

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index)
        public
        view
        virtual
        override
        returns (uint256)
    {
        require(
            index < ERC721.balanceOf(owner),
            "ERC721Enumerable: owner index out of bounds"
        );
        return _ownedTokens[owner][index];
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index)
        public
        view
        virtual
        override
        returns (uint256)
    {
        require(
            index < ERC721Enumerable.totalSupply(),
            "ERC721Enumerable: global index out of bounds"
        );
        return _allTokens[index];
    }

    /**
     * @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 override {
        super._beforeTokenTransfer(from, to, tokenId);

        if (from == address(0)) {
            _addTokenToAllTokensEnumeration(tokenId);
        } else if (from != to) {
            _removeTokenFromOwnerEnumeration(from, tokenId);
        }
        if (to == address(0)) {
            _removeTokenFromAllTokensEnumeration(tokenId);
        } else if (to != from) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        uint256 length = ERC721.balanceOf(to);
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId)
        private
    {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }
}

pragma solidity ^0.8.0;

/**
 * @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() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual 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 {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(
            newOwner != address(0),
            "Ownable: new owner is the zero address"
        );
        _transferOwnership(newOwner);
    }

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

pragma solidity ^0.8.0;

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is
    IAccessControlEnumerable,
    AccessControl
{
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;

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

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index)
        public
        view
        virtual
        override
        returns (address)
    {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role)
        public
        view
        virtual
        override
        returns (uint256)
    {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account)
        internal
        virtual
        override
    {
        super._grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account)
        internal
        virtual
        override
    {
        super._revokeRole(role, account);
        _roleMembers[role].remove(account);
    }
}

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

pragma solidity ^0.8.4;

error ApprovalCallerNotOwnerNorApproved();
error ApprovalQueryForNonexistentToken();
error ApproveToCaller();
error ApprovalToCurrentOwner();
error BalanceQueryForZeroAddress();
error MintToZeroAddress();
error MintZeroQuantity();
error OwnerQueryForNonexistentToken();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TransferToNonERC721ReceiverImplementer();
error TransferToZeroAddress();
error URIQueryForNonexistentToken();

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension. Built to optimize for lower gas during batch mints.
 *
 * Assumes serials are sequentially minted starting at _startTokenId() (defaults to 0, e.g. 0, 1, 2, 3..).
 *
 * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
 *
 * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256).
 */
contract ERC721A is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Compiler will pack this into a single 256bit word.
    struct TokenOwnership {
        // The address of the owner.
        address addr;
        // Keeps track of the start time of ownership with minimal overhead for tokenomics.
        uint64 startTimestamp;
        // Whether the token has been burned.
        bool burned;
    }

    // Compiler will pack this into a single 256bit word.
    struct AddressData {
        // Realistically, 2**64-1 is more than enough.
        uint64 balance;
        // Keeps track of mint count with minimal overhead for tokenomics.
        uint64 numberMinted;
        // Keeps track of burn count with minimal overhead for tokenomics.
        uint64 numberBurned;
        // For miscellaneous variable(s) pertaining to the address
        // (e.g. number of whitelist mint slots used).
        // If there are multiple variables, please pack them into a uint64.
        uint64 aux;
    }

    // The tokenId of the next token to be minted.
    uint256 internal _currentIndex;

    // The number of tokens burned.
    uint256 internal _burnCounter;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to ownership details
    // An empty struct value does not necessarily mean the token is unowned. See _ownershipOf implementation for details.
    mapping(uint256 => TokenOwnership) internal _ownerships;

    // Mapping owner address to address data
    mapping(address => AddressData) private _addressData;

    // 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;

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _currentIndex = _startTokenId();
    }

    /**
     * To change the starting tokenId, please override this function.
     */
    function _startTokenId() internal view virtual returns (uint256) {
        return 0;
    }

    /**
     * @dev Burned tokens are calculated here, use _totalMinted() if you want to count just minted tokens.
     */
    function totalSupply() public view returns (uint256) {
        // Counter underflow is impossible as _burnCounter cannot be incremented
        // more than _currentIndex - _startTokenId() times
        unchecked {
            return _currentIndex - _burnCounter - _startTokenId();
        }
    }

    /**
     * Returns the total amount of tokens minted in the contract.
     */
    function _totalMinted() internal view returns (uint256) {
        // Counter underflow is impossible as _currentIndex does not decrement,
        // and it is initialized to _startTokenId()
        unchecked {
            return _currentIndex - _startTokenId();
        }
    }

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

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view override returns (uint256) {
        if (owner == address(0)) revert BalanceQueryForZeroAddress();
        return uint256(_addressData[owner].balance);
    }

    /**
     * Returns the number of tokens minted by `owner`.
     */
    function _numberMinted(address owner) internal view returns (uint256) {
        return uint256(_addressData[owner].numberMinted);
    }

    /**
     * Returns the number of tokens burned by or on behalf of `owner`.
     */
    function _numberBurned(address owner) internal view returns (uint256) {
        return uint256(_addressData[owner].numberBurned);
    }

    /**
     * Returns the auxillary data for `owner`. (e.g. number of whitelist mint slots used).
     */
    function _getAux(address owner) internal view returns (uint64) {
        return _addressData[owner].aux;
    }

    /**
     * Sets the auxillary data for `owner`. (e.g. number of whitelist mint slots used).
     * If there are multiple variables, please pack them into a uint64.
     */
    function _setAux(address owner, uint64 aux) internal {
        _addressData[owner].aux = aux;
    }

    /**
     * Gas spent here starts off proportional to the maximum mint batch size.
     * It gradually moves to O(1) as tokens get transferred around in the collection over time.
     */
    function _ownershipOf(uint256 tokenId)
        internal
        view
        returns (TokenOwnership memory)
    {
        uint256 curr = tokenId;

        unchecked {
            if (_startTokenId() <= curr && curr < _currentIndex) {
                TokenOwnership memory ownership = _ownerships[curr];
                if (!ownership.burned) {
                    if (ownership.addr != address(0)) {
                        return ownership;
                    }
                    // Invariant:
                    // There will always be an ownership that has an address and is not burned
                    // before an ownership that does not have an address and is not burned.
                    // Hence, curr will not underflow.
                    while (true) {
                        curr--;
                        ownership = _ownerships[curr];
                        if (ownership.addr != address(0)) {
                            return ownership;
                        }
                    }
                }
            }
        }
        revert OwnerQueryForNonexistentToken();
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view override returns (address) {
        return _ownershipOf(tokenId).addr;
    }

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

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

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId)
        public
        view
        virtual
        override
        returns (string memory)
    {
        if (!_exists(tokenId)) revert URIQueryForNonexistentToken();

        string memory baseURI = _baseURI();
        return
            bytes(baseURI).length != 0
                ? string(abi.encodePacked(baseURI, tokenId.toString()))
                : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public override {
        address owner = ERC721A.ownerOf(tokenId);
        if (to == owner) revert ApprovalToCurrentOwner();

        if (_msgSender() != owner && !isApprovedForAll(owner, _msgSender())) {
            revert ApprovalCallerNotOwnerNorApproved();
        }

        _approve(to, tokenId, owner);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId)
        public
        view
        override
        returns (address)
    {
        if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved)
        public
        virtual
        override
    {
        if (operator == _msgSender()) revert ApproveToCaller();

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

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

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        _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 {
        _transfer(from, to, tokenId);
        if (
            to.isContract() &&
            !_checkContractOnERC721Received(from, to, tokenId, _data)
        ) {
            revert TransferToNonERC721ReceiverImplementer();
        }
    }

    /**
     * @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`),
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        return
            _startTokenId() <= tokenId &&
            tokenId < _currentIndex &&
            !_ownerships[tokenId].burned;
    }

    function _safeMint(address to, uint256 quantity) internal {
        _safeMint(to, quantity, "");
    }

    /**
     * @dev Safely mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal {
        _mint(to, quantity, _data, true);
    }

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event.
     */
    function _mint(
        address to,
        uint256 quantity,
        bytes memory _data,
        bool safe
    ) internal {
        uint256 startTokenId = _currentIndex;
        if (to == address(0)) revert MintToZeroAddress();
        if (quantity == 0) revert MintZeroQuantity();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are incredibly unrealistic.
        // balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1
        // updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1
        unchecked {
            _addressData[to].balance += uint64(quantity);
            _addressData[to].numberMinted += uint64(quantity);

            _ownerships[startTokenId].addr = to;
            _ownerships[startTokenId].startTimestamp = uint64(block.timestamp);

            uint256 updatedIndex = startTokenId;
            uint256 end = updatedIndex + quantity;

            if (safe && to.isContract()) {
                do {
                    emit Transfer(address(0), to, updatedIndex);
                    if (
                        !_checkContractOnERC721Received(
                            address(0),
                            to,
                            updatedIndex++,
                            _data
                        )
                    ) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
                } while (updatedIndex != end);
                // Reentrancy protection
                if (_currentIndex != startTokenId) revert();
            } else {
                do {
                    emit Transfer(address(0), to, updatedIndex++);
                } while (updatedIndex != end);
            }
            _currentIndex = updatedIndex;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * 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
    ) private {
        TokenOwnership memory prevOwnership = _ownershipOf(tokenId);

        if (prevOwnership.addr != from) revert TransferFromIncorrectOwner();

        bool isApprovedOrOwner = (_msgSender() == from ||
            isApprovedForAll(from, _msgSender()) ||
            getApproved(tokenId) == _msgSender());

        if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
        if (to == address(0)) revert TransferToZeroAddress();

        _beforeTokenTransfers(from, to, tokenId, 1);

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

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256.
        unchecked {
            _addressData[from].balance -= 1;
            _addressData[to].balance += 1;

            TokenOwnership storage currSlot = _ownerships[tokenId];
            currSlot.addr = to;
            currSlot.startTimestamp = uint64(block.timestamp);

            // If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.
            // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
            uint256 nextTokenId = tokenId + 1;
            TokenOwnership storage nextSlot = _ownerships[nextTokenId];
            if (nextSlot.addr == address(0)) {
                // This will suffice for checking _exists(nextTokenId),
                // as a burned slot cannot contain the zero address.
                if (nextTokenId != _currentIndex) {
                    nextSlot.addr = from;
                    nextSlot.startTimestamp = prevOwnership.startTimestamp;
                }
            }
        }

        emit Transfer(from, to, tokenId);
        _afterTokenTransfers(from, to, tokenId, 1);
    }

    /**
     * @dev This is equivalent to _burn(tokenId, false)
     */
    function _burn(uint256 tokenId) internal virtual {
        _burn(tokenId, false);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
        TokenOwnership memory prevOwnership = _ownershipOf(tokenId);

        address from = prevOwnership.addr;

        if (approvalCheck) {
            bool isApprovedOrOwner = (_msgSender() == from ||
                isApprovedForAll(from, _msgSender()) ||
                getApproved(tokenId) == _msgSender());

            if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
        }

        _beforeTokenTransfers(from, address(0), tokenId, 1);

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

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256.
        unchecked {
            AddressData storage addressData = _addressData[from];
            addressData.balance -= 1;
            addressData.numberBurned += 1;

            // Keep track of who burned the token, and the timestamp of burning.
            TokenOwnership storage currSlot = _ownerships[tokenId];
            currSlot.addr = from;
            currSlot.startTimestamp = uint64(block.timestamp);
            currSlot.burned = true;

            // If the ownership slot of tokenId+1 is not explicitly set, that means the burn initiator owns it.
            // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
            uint256 nextTokenId = tokenId + 1;
            TokenOwnership storage nextSlot = _ownerships[nextTokenId];
            if (nextSlot.addr == address(0)) {
                // This will suffice for checking _exists(nextTokenId),
                // as a burned slot cannot contain the zero address.
                if (nextTokenId != _currentIndex) {
                    nextSlot.addr = from;
                    nextSlot.startTimestamp = prevOwnership.startTimestamp;
                }
            }
        }

        emit Transfer(from, address(0), tokenId);
        _afterTokenTransfers(from, address(0), tokenId, 1);

        // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
        unchecked {
            _burnCounter++;
        }
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(
        address to,
        uint256 tokenId,
        address owner
    ) private {
        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target 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 _checkContractOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        try
            IERC721Receiver(to).onERC721Received(
                _msgSender(),
                from,
                tokenId,
                _data
            )
        returns (bytes4 retval) {
            return retval == IERC721Receiver(to).onERC721Received.selector;
        } catch (bytes memory reason) {
            if (reason.length == 0) {
                revert TransferToNonERC721ReceiverImplementer();
            } else {
                assembly {
                    revert(add(32, reason), mload(reason))
                }
            }
        }
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
     * And also called before burning one token.
     *
     * startTokenId - the first token id to be transferred
     * quantity - the amount to be transferred
     *
     * 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, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
     * minting.
     * And also called after one token has been burned.
     *
     * startTokenId - the first token id to be transferred
     * quantity - the amount to be transferred
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
     * transferred to `to`.
     * - When `from` is zero, `tokenId` has been minted for `to`.
     * - When `to` is zero, `tokenId` has been burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}
}

pragma solidity ^0.8.0;

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

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

    /**
     * @dev Returns the 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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from,
        address to,
        uint256 amount
    ) external returns (bool);
}

pragma solidity ^0.8.0;

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

    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'
        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) + value;
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(
                token.approve.selector,
                spender,
                newAllowance
            )
        );
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(
                oldAllowance >= value,
                "SafeERC20: decreased allowance below zero"
            );
            uint256 newAllowance = oldAllowance - value;
            _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
            require(
                abi.decode(returndata, (bool)),
                "SafeERC20: ERC20 operation did not succeed"
            );
        }
    }
}

pragma solidity ^0.8.0;

/**
 * @title PaymentSplitter
 * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware
 * that the Ether will be split in this way, since it is handled transparently by the contract.
 *
 * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each
 * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim
 * an amount proportional to the percentage of total shares they were assigned.
 *
 * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the
 * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release}
 * function.
 *
 * NOTE: This contract assumes that ERC20 tokens will behave similarly to native tokens (Ether). Rebasing tokens, and
 * tokens that apply fees during transfers, are likely to not be supported as expected. If in doubt, we encourage you
 * to run tests before sending real value to this contract.
 */
contract PaymentSplitter is Context {
    event PayeeAdded(address account, uint256 shares);
    event PaymentReleased(address to, uint256 amount);
    event ERC20PaymentReleased(
        IERC20 indexed token,
        address to,
        uint256 amount
    );
    event PaymentReceived(address from, uint256 amount);

    uint256 private _totalShares;
    uint256 private _totalReleased;

    mapping(address => uint256) private _shares;
    mapping(address => uint256) private _released;
    address[] private _payees;

    mapping(IERC20 => uint256) private _erc20TotalReleased;
    mapping(IERC20 => mapping(address => uint256)) private _erc20Released;

    /**
     * @dev Creates an instance of `PaymentSplitter` where each account in `payees` is assigned the number of shares at
     * the matching position in the `shares` array.
     *
     * All addresses in `payees` must be non-zero. Both arrays must have the same non-zero length, and there must be no
     * duplicates in `payees`.
     */
    constructor(address[] memory payees, uint256[] memory shares_) payable {
        require(
            payees.length == shares_.length,
            "PaymentSplitter: payees and shares length mismatch"
        );
        require(payees.length > 0, "PaymentSplitter: no payees");

        for (uint256 i = 0; i < payees.length; i++) {
            _addPayee(payees[i], shares_[i]);
        }
    }

    /**
     * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully
     * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the
     * reliability of the events, and not the actual splitting of Ether.
     *
     * To learn more about this see the Solidity documentation for
     * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback
     * functions].
     */
    receive() external payable virtual {
        emit PaymentReceived(_msgSender(), msg.value);
    }

    /**
     * @dev Getter for the total shares held by payees.
     */
    function totalShares() public view returns (uint256) {
        return _totalShares;
    }

    /**
     * @dev Getter for the total amount of Ether already released.
     */
    function totalReleased() public view returns (uint256) {
        return _totalReleased;
    }

    /**
     * @dev Getter for the total amount of `token` already released. `token` should be the address of an IERC20
     * contract.
     */
    function totalReleased(IERC20 token) public view returns (uint256) {
        return _erc20TotalReleased[token];
    }

    /**
     * @dev Getter for the amount of shares held by an account.
     */
    function shares(address account) public view returns (uint256) {
        return _shares[account];
    }

    /**
     * @dev Getter for the amount of Ether already released to a payee.
     */
    function released(address account) public view returns (uint256) {
        return _released[account];
    }

    /**
     * @dev Getter for the amount of `token` tokens already released to a payee. `token` should be the address of an
     * IERC20 contract.
     */
    function released(IERC20 token, address account)
        public
        view
        returns (uint256)
    {
        return _erc20Released[token][account];
    }

    /**
     * @dev Getter for the address of the payee number `index`.
     */
    function payee(uint256 index) public view returns (address) {
        return _payees[index];
    }

    /**
     * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the
     * total shares and their previous withdrawals.
     */
    function release(address payable account) public virtual {
        require(_shares[account] > 0, "PaymentSplitter: account has no shares");

        uint256 totalReceived = address(this).balance + totalReleased();
        uint256 payment = _pendingPayment(
            account,
            totalReceived,
            released(account)
        );

        require(payment != 0, "PaymentSplitter: account is not due payment");

        _released[account] += payment;
        _totalReleased += payment;

        Address.sendValue(account, payment);
        emit PaymentReleased(account, payment);
    }

    /**
     * @dev Triggers a transfer to `account` of the amount of `token` tokens they are owed, according to their
     * percentage of the total shares and their previous withdrawals. `token` must be the address of an IERC20
     * contract.
     */
    function release(IERC20 token, address account) public virtual {
        require(_shares[account] > 0, "PaymentSplitter: account has no shares");

        uint256 totalReceived = token.balanceOf(address(this)) +
            totalReleased(token);
        uint256 payment = _pendingPayment(
            account,
            totalReceived,
            released(token, account)
        );

        require(payment != 0, "PaymentSplitter: account is not due payment");

        _erc20Released[token][account] += payment;
        _erc20TotalReleased[token] += payment;

        SafeERC20.safeTransfer(token, account, payment);
        emit ERC20PaymentReleased(token, account, payment);
    }

    /**
     * @dev internal logic for computing the pending payment of an `account` given the token historical balances and
     * already released amounts.
     */
    function _pendingPayment(
        address account,
        uint256 totalReceived,
        uint256 alreadyReleased
    ) private view returns (uint256) {
        return
            (totalReceived * _shares[account]) / _totalShares - alreadyReleased;
    }

    /**
     * @dev Add a new payee to the contract.
     * @param account The address of the payee to add.
     * @param shares_ The number of shares owned by the payee.
     */
    function _addPayee(address account, uint256 shares_) private {
        require(
            account != address(0),
            "PaymentSplitter: account is the zero address"
        );
        require(shares_ > 0, "PaymentSplitter: shares are 0");
        require(
            _shares[account] == 0,
            "PaymentSplitter: account already has shares"
        );

        _payees.push(account);
        _shares[account] = shares_;
        _totalShares = _totalShares + shares_;
        emit PayeeAdded(account, shares_);
    }
}

pragma solidity ^0.8.0;

contract LiquidKeys is ERC721A, ReentrancyGuard, Ownable, PaymentSplitter {
    // Minting Variables
    uint256 public mintPrice = 0.420 ether;
    uint256 public maxPurchase = 1;
    uint256 public maxSupply = 3333;

    address[] public _payees = [
        0x7FDE663601A53A6953bbb98F1Ab87E86dEE81b35, // Liquid Payments
        0x867Eb0804eACA9FEeda8a0E1d2B9a32eEF58AF8f // Aleph0ne
    ];
    uint256[] private _shares = [10, 90];

    // Sale Status
    bool public saleIsActive = false;
    bool public airdropIsActive = true;

    mapping(address => uint256) public addressesThatMinted;

    // Metadata
    string _baseTokenURI =
        "https://apeliquid.mypinata.cloud/ipfs/QmPT8KDtweNFx1EqtFdaYhkrvAGeAGoY1ubCGxKx8spDur/";
    bool public locked;

    // Events
    event SaleActivation(bool isActive);
    event AirdropActivation(bool isActive);

    constructor()
        ERC721A("Liquid Key", "ALKEY")
        PaymentSplitter(_payees, _shares)
    {}

    //Holder status validation

    // Minting
    function ownerMint(address _to, uint256 _count) external onlyOwner {
        require(totalSupply() + _count <= maxSupply, "SOLD OUT");
        _safeMint(_to, _count);
    }

    function airdrop(uint256[] calldata _counts, address[] calldata _list)
        external
        onlyOwner
    {
        require(airdropIsActive, "AIRDROP NOT ACTIVE");

        for (uint256 i = 0; i < _list.length; i++) {
            //_mint(_list[i], _dropNumber, 1, "");
            require(totalSupply() + _counts[i] <= maxSupply, "SOLD OUT");
            _safeMint(_list[i], _counts[i]);
        }
    }

    function mint(uint256 _count) external payable nonReentrant {
        require(saleIsActive, "SALE INACTIVE");
        require(
            ((addressesThatMinted[msg.sender] + _count)) <= maxPurchase,
            "this would exceed mint max allowance"
        );

        require(totalSupply() + _count <= maxSupply, "SOLD OUT");
        require(mintPrice * _count <= msg.value, "INCORRECT ETHER VALUE");

        _safeMint(msg.sender, _count);
        addressesThatMinted[msg.sender] += _count;
    }

    function toggleSaleStatus() external onlyOwner {
        saleIsActive = !saleIsActive;
        emit SaleActivation(saleIsActive);
    }

    function toggleAirdropStatus() external onlyOwner {
        airdropIsActive = !airdropIsActive;
        emit AirdropActivation(airdropIsActive);
    }

    function setMintPrice(uint256 _mintPrice) external onlyOwner {
        mintPrice = _mintPrice;
    }

    function setMaxPurchase(uint256 _maxPurchase) external onlyOwner {
        maxPurchase = _maxPurchase;
    }

    function lockMetadata() external onlyOwner {
        locked = true;
    }

    // Payment
    function claim() external {
        release(payable(msg.sender));
    }

    function getWalletOfOwner(address owner)
        external
        view
        returns (uint256[] memory)
    {
        unchecked {
            uint256[] memory a = new uint256[](balanceOf(owner));
            uint256 end = _currentIndex;
            uint256 tokenIdsIdx;
            address currOwnershipAddr;
            for (uint256 i; i < end; i++) {
                TokenOwnership memory ownership = _ownerships[i];
                if (ownership.burned) {
                    continue;
                }
                if (ownership.addr != address(0)) {
                    currOwnershipAddr = ownership.addr;
                }
                if (currOwnershipAddr == owner) {
                    a[tokenIdsIdx++] = i;
                }
            }
            return a;
        }
    }

    function getTotalSupply() external view returns (uint256) {
        return totalSupply();
    }

    function setBaseURI(string memory baseURI) external onlyOwner {
        require(!locked, "METADATA_LOCKED");
        _baseTokenURI = baseURI;
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return _baseTokenURI;
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override
        returns (string memory)
    {
        return string(abi.encodePacked(super.tokenURI(tokenId), ".json"));
    }

    function _startTokenId() internal view virtual override returns (uint256) {
        return 1;
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApprovalToCurrentOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"}],"name":"AirdropActivation","type":"event"},{"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":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20PaymentReleased","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":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"PayeeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PaymentReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PaymentReleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"}],"name":"SaleActivation","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":"uint256","name":"","type":"uint256"}],"name":"_payees","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressesThatMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_counts","type":"uint256[]"},{"internalType":"address[]","name":"_list","type":"address[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"airdropIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","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":[],"name":"getTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getWalletOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"locked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPurchase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_count","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_count","type":"uint256"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"payee","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"account","type":"address"}],"name":"release","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"release","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"released","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"released","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"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":[],"name":"saleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPurchase","type":"uint256"}],"name":"setMaxPurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintPrice","type":"uint256"}],"name":"setMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"shares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleAirdropStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleSaleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"totalReleased","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReleased","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040526705d423c655aa00006011556001601255610d056013556040518060400160405280737fde663601a53a6953bbb98f1ab87e86dee81b3573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200173867eb0804eaca9feeda8a0e1d2b9a32eef58af8f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152506014906002620000c29291906200073a565b506040518060400160405280600a60ff168152602001605a60ff168152506015906002620000f2929190620007c9565b506000601660006101000a81548160ff0219169083151502179055506001601660016101000a81548160ff0219169083151502179055506040518060800160405280605581526020016200622c60559139601890805190602001906200015a92919062000820565b503480156200016857600080fd5b506014805480602002602001604051908101604052809291908181526020018280548015620001ed57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311620001a2575b505050505060158054806020026020016040519081016040528092919081815260200182805480156200024057602002820191906000526020600020905b8154815260200190600101908083116200022b575b50505050506040518060400160405280600a81526020017f4c6971756964204b6579000000000000000000000000000000000000000000008152506040518060400160405280600581526020017f414c4b45590000000000000000000000000000000000000000000000000000008152508160029080519060200190620002c992919062000820565b508060039080519060200190620002e292919062000820565b50620002f36200042960201b60201c565b6000819055505050600160088190555062000323620003176200043260201b60201c565b6200043a60201b60201c565b80518251146200036a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003619062000957565b60405180910390fd5b6000825111620003b1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003a890620009c9565b60405180910390fd5b60005b825181101562000420576200040a838281518110620003d857620003d7620009eb565b5b6020026020010151838381518110620003f657620003f5620009eb565b5b60200260200101516200050060201b60201c565b8080620004179062000a53565b915050620003b4565b50505062000d88565b60006001905090565b600033905090565b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141562000573576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200056a9062000b17565b60405180910390fd5b60008111620005b9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620005b09062000b89565b60405180910390fd5b6000600c60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054146200063e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620006359062000c21565b60405180910390fd5b600e829080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600c60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080600a54620006f5919062000c43565b600a819055507f40c340f65e17194d14ddddb073d3c9f888e3cb52b5aae0c6c7706b4fbc905fac82826040516200072e92919062000cf6565b60405180910390a15050565b828054828255906000526020600020908101928215620007b6579160200282015b82811115620007b55782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906200075b565b5b509050620007c59190620008b1565b5090565b8280548282559060005260206000209081019282156200080d579160200282015b828111156200080c578251829060ff16905591602001919060010190620007ea565b5b5090506200081c9190620008b1565b5090565b8280546200082e9062000d52565b90600052602060002090601f0160209004810192826200085257600085556200089e565b82601f106200086d57805160ff19168380011785556200089e565b828001600101855582156200089e579182015b828111156200089d57825182559160200191906001019062000880565b5b509050620008ad9190620008b1565b5090565b5b80821115620008cc576000816000905550600101620008b2565b5090565b600082825260208201905092915050565b7f5061796d656e7453706c69747465723a2070617965657320616e64207368617260008201527f6573206c656e677468206d69736d617463680000000000000000000000000000602082015250565b60006200093f603283620008d0565b91506200094c82620008e1565b604082019050919050565b60006020820190508181036000830152620009728162000930565b9050919050565b7f5061796d656e7453706c69747465723a206e6f20706179656573000000000000600082015250565b6000620009b1601a83620008d0565b9150620009be8262000979565b602082019050919050565b60006020820190508181036000830152620009e481620009a2565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000819050919050565b600062000a608262000a49565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141562000a965762000a9562000a1a565b5b600182019050919050565b7f5061796d656e7453706c69747465723a206163636f756e74206973207468652060008201527f7a65726f20616464726573730000000000000000000000000000000000000000602082015250565b600062000aff602c83620008d0565b915062000b0c8262000aa1565b604082019050919050565b6000602082019050818103600083015262000b328162000af0565b9050919050565b7f5061796d656e7453706c69747465723a20736861726573206172652030000000600082015250565b600062000b71601d83620008d0565b915062000b7e8262000b39565b602082019050919050565b6000602082019050818103600083015262000ba48162000b62565b9050919050565b7f5061796d656e7453706c69747465723a206163636f756e7420616c726561647960008201527f2068617320736861726573000000000000000000000000000000000000000000602082015250565b600062000c09602b83620008d0565b915062000c168262000bab565b604082019050919050565b6000602082019050818103600083015262000c3c8162000bfa565b9050919050565b600062000c508262000a49565b915062000c5d8362000a49565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111562000c955762000c9462000a1a565b5b828201905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600062000ccd8262000ca0565b9050919050565b62000cdf8162000cc0565b82525050565b62000cf08162000a49565b82525050565b600060408201905062000d0d600083018562000cd4565b62000d1c602083018462000ce5565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168062000d6b57607f821691505b6020821081141562000d825762000d8162000d23565b5b50919050565b6154948062000d986000396000f3fe6080604052600436106102815760003560e01c80638b83209b1161014f578063c4e41b22116100c1578063e33b7de31161007a578063e33b7de3146109fa578063e985e9c514610a25578063eb8d244414610a62578063ef6d492714610a8d578063f2fde38b14610aa4578063f4a0a52814610acd576102c8565b8063c4e41b22146108c2578063c87b56dd146108ed578063ce7c2ac21461092a578063cf30901214610967578063d5abeb0114610992578063d79779b2146109bd576102c8565b8063989bdbb611610113578063989bdbb6146107d5578063a0712d68146107ec578063a22cb46514610808578063aa3f395514610831578063ab2fdb0c1461085c578063b88d4fde14610899576102c8565b80638b83209b146106da5780638da5cb5b1461071757806395d89b4114610742578063977b055b1461076d5780639852595c14610798576102c8565b806342842e0e116101f35780636352211e116101ac5780636352211e146105cc5780636673c4c2146106095780636817c76c1461063257806370a082311461065d578063711897421461069a578063715018a6146106c3576102c8565b806342842e0e146104d4578063484b973c146104fd57806348b75044146105265780634e71d92d1461054f57806355f804b314610566578063627fdeab1461058f576102c8565b806318160ddd1161024557806318160ddd146103b257806319165587146103dd57806323b872dd14610406578063283248be1461042f5780633a98ef391461046c578063406072a914610497576102c8565b806301ffc9a7146102cd578063049c5c491461030a57806306fdde0314610321578063081812fc1461034c578063095ea7b314610389576102c8565b366102c8577f6ef95f06320e7a25a04a175ca677b7052bdd97131872c2192525a629f51be7706102af610af6565b346040516102be929190613d23565b60405180910390a1005b600080fd5b3480156102d957600080fd5b506102f460048036038101906102ef9190613db8565b610afe565b6040516103019190613e00565b60405180910390f35b34801561031657600080fd5b5061031f610be0565b005b34801561032d57600080fd5b50610336610cce565b6040516103439190613eb4565b60405180910390f35b34801561035857600080fd5b50610373600480360381019061036e9190613f02565b610d60565b6040516103809190613f2f565b60405180910390f35b34801561039557600080fd5b506103b060048036038101906103ab9190613f76565b610ddc565b005b3480156103be57600080fd5b506103c7610ee7565b6040516103d49190613fb6565b60405180910390f35b3480156103e957600080fd5b5061040460048036038101906103ff919061400f565b610efe565b005b34801561041257600080fd5b5061042d6004803603810190610428919061403c565b6110a9565b005b34801561043b57600080fd5b5061045660048036038101906104519190613f02565b6110b9565b6040516104639190613f2f565b60405180910390f35b34801561047857600080fd5b506104816110f8565b60405161048e9190613fb6565b60405180910390f35b3480156104a357600080fd5b506104be60048036038101906104b991906140cd565b611102565b6040516104cb9190613fb6565b60405180910390f35b3480156104e057600080fd5b506104fb60048036038101906104f6919061403c565b611189565b005b34801561050957600080fd5b50610524600480360381019061051f9190613f76565b6111a9565b005b34801561053257600080fd5b5061054d600480360381019061054891906140cd565b61128a565b005b34801561055b57600080fd5b50610564611543565b005b34801561057257600080fd5b5061058d60048036038101906105889190614242565b61154e565b005b34801561059b57600080fd5b506105b660048036038101906105b1919061428b565b611634565b6040516105c39190614376565b60405180910390f35b3480156105d857600080fd5b506105f360048036038101906105ee9190613f02565b61182b565b6040516106009190613f2f565b60405180910390f35b34801561061557600080fd5b50610630600480360381019061062b919061444e565b611841565b005b34801561063e57600080fd5b506106476119ee565b6040516106549190613fb6565b60405180910390f35b34801561066957600080fd5b50610684600480360381019061067f919061428b565b6119f4565b6040516106919190613fb6565b60405180910390f35b3480156106a657600080fd5b506106c160048036038101906106bc9190613f02565b611ac4565b005b3480156106cf57600080fd5b506106d8611b4a565b005b3480156106e657600080fd5b5061070160048036038101906106fc9190613f02565b611bd2565b60405161070e9190613f2f565b60405180910390f35b34801561072357600080fd5b5061072c611c1a565b6040516107399190613f2f565b60405180910390f35b34801561074e57600080fd5b50610757611c44565b6040516107649190613eb4565b60405180910390f35b34801561077957600080fd5b50610782611cd6565b60405161078f9190613fb6565b60405180910390f35b3480156107a457600080fd5b506107bf60048036038101906107ba919061428b565b611cdc565b6040516107cc9190613fb6565b60405180910390f35b3480156107e157600080fd5b506107ea611d25565b005b61080660048036038101906108019190613f02565b611dbe565b005b34801561081457600080fd5b5061082f600480360381019061082a91906144fb565b611ffc565b005b34801561083d57600080fd5b50610846612174565b6040516108539190613e00565b60405180910390f35b34801561086857600080fd5b50610883600480360381019061087e919061428b565b612187565b6040516108909190613fb6565b60405180910390f35b3480156108a557600080fd5b506108c060048036038101906108bb91906145dc565b61219f565b005b3480156108ce57600080fd5b506108d761221b565b6040516108e49190613fb6565b60405180910390f35b3480156108f957600080fd5b50610914600480360381019061090f9190613f02565b61222a565b6040516109219190613eb4565b60405180910390f35b34801561093657600080fd5b50610951600480360381019061094c919061428b565b61225b565b60405161095e9190613fb6565b60405180910390f35b34801561097357600080fd5b5061097c6122a4565b6040516109899190613e00565b60405180910390f35b34801561099e57600080fd5b506109a76122b7565b6040516109b49190613fb6565b60405180910390f35b3480156109c957600080fd5b506109e460048036038101906109df919061465f565b6122bd565b6040516109f19190613fb6565b60405180910390f35b348015610a0657600080fd5b50610a0f612306565b604051610a1c9190613fb6565b60405180910390f35b348015610a3157600080fd5b50610a4c6004803603810190610a47919061468c565b612310565b604051610a599190613e00565b60405180910390f35b348015610a6e57600080fd5b50610a776123a4565b604051610a849190613e00565b60405180910390f35b348015610a9957600080fd5b50610aa26123b7565b005b348015610ab057600080fd5b50610acb6004803603810190610ac6919061428b565b6124a5565b005b348015610ad957600080fd5b50610af46004803603810190610aef9190613f02565b61259d565b005b600033905090565b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610bc957507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610bd95750610bd882612623565b5b9050919050565b610be8610af6565b73ffffffffffffffffffffffffffffffffffffffff16610c06611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614610c5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5390614718565b60405180910390fd5b601660009054906101000a900460ff1615601660006101000a81548160ff0219169083151502179055507f58655b75d3df612fe99ead00dbf0812d415d35078fe06217a94c0818bb13967f601660009054906101000a900460ff16604051610cc49190613e00565b60405180910390a1565b606060028054610cdd90614767565b80601f0160208091040260200160405190810160405280929190818152602001828054610d0990614767565b8015610d565780601f10610d2b57610100808354040283529160200191610d56565b820191906000526020600020905b815481529060010190602001808311610d3957829003601f168201915b5050505050905090565b6000610d6b8261268d565b610da1576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000610de78261182b565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610e4f576040517f943f7b8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610e6e610af6565b73ffffffffffffffffffffffffffffffffffffffff1614158015610ea05750610e9e81610e99610af6565b612310565b155b15610ed7576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ee28383836126db565b505050565b6000610ef161278d565b6001546000540303905090565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411610f80576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f779061480b565b60405180910390fd5b6000610f8a612306565b47610f95919061485a565b90506000610fac8383610fa786611cdc565b612796565b90506000811415610ff2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe990614922565b60405180910390fd5b80600d60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611041919061485a565b9250508190555080600b600082825461105a919061485a565b9250508190555061106b8382612804565b7fdf20fd1e76bc69d672e4814fafb2c449bba3a5369d8359adf9e05e6fde87b056838260405161109c9291906149a1565b60405180910390a1505050565b6110b48383836128f8565b505050565b601481815481106110c957600080fd5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600a54905090565b6000601060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6111a48383836040518060200160405280600081525061219f565b505050565b6111b1610af6565b73ffffffffffffffffffffffffffffffffffffffff166111cf611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614611225576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121c90614718565b60405180910390fd5b60135481611231610ee7565b61123b919061485a565b111561127c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161127390614a16565b60405180910390fd5b6112868282612dae565b5050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541161130c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113039061480b565b60405180910390fd5b6000611317836122bd565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016113509190613f2f565b602060405180830381865afa15801561136d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113919190614a4b565b61139b919061485a565b905060006113b383836113ae8787611102565b612796565b905060008114156113f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113f090614922565b60405180910390fd5b80601060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611485919061485a565b9250508190555080600f60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546114db919061485a565b925050819055506114ed848483612dcc565b8373ffffffffffffffffffffffffffffffffffffffff167f3be5b7a71e84ed12875d241991c70855ac5817d847039e17a9d895c1ceb0f18a8483604051611535929190613d23565b60405180910390a250505050565b61154c33610efe565b565b611556610af6565b73ffffffffffffffffffffffffffffffffffffffff16611574611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146115ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115c190614718565b60405180910390fd5b601960009054906101000a900460ff161561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161161190614ac4565b60405180910390fd5b8060189080519060200190611630929190613be3565b5050565b60606000611641836119f4565b67ffffffffffffffff81111561165a57611659614117565b5b6040519080825280602002602001820160405280156116885781602001602082028036833780820191505090505b50905060008054905060008060005b8381101561181e576000600460008381526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815260200160008201601c9054906101000a900460ff16151515158152505090508060400151156117745750611811565b600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16146117b457806000015192505b8773ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561180f578186858060010196508151811061180257611801614ae4565b5b6020026020010181815250505b505b8080600101915050611697565b5083945050505050919050565b600061183682612e52565b600001519050919050565b611849610af6565b73ffffffffffffffffffffffffffffffffffffffff16611867611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146118bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118b490614718565b60405180910390fd5b601660019054906101000a900460ff1661190c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161190390614b5f565b60405180910390fd5b60005b828290508110156119e7576013548585838181106119305761192f614ae4565b5b9050602002013561193f610ee7565b611949919061485a565b111561198a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161198190614a16565b60405180910390fd5b6119d48383838181106119a05761199f614ae4565b5b90506020020160208101906119b5919061428b565b8686848181106119c8576119c7614ae4565b5b90506020020135612dae565b80806119df90614b7f565b91505061190f565b5050505050565b60115481565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611a5c576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900467ffffffffffffffff1667ffffffffffffffff169050919050565b611acc610af6565b73ffffffffffffffffffffffffffffffffffffffff16611aea611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614611b40576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b3790614718565b60405180910390fd5b8060128190555050565b611b52610af6565b73ffffffffffffffffffffffffffffffffffffffff16611b70611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614611bc6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bbd90614718565b60405180910390fd5b611bd060006130e1565b565b6000600e8281548110611be857611be7614ae4565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060038054611c5390614767565b80601f0160208091040260200160405190810160405280929190818152602001828054611c7f90614767565b8015611ccc5780601f10611ca157610100808354040283529160200191611ccc565b820191906000526020600020905b815481529060010190602001808311611caf57829003601f168201915b5050505050905090565b60125481565b6000600d60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b611d2d610af6565b73ffffffffffffffffffffffffffffffffffffffff16611d4b611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614611da1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d9890614718565b60405180910390fd5b6001601960006101000a81548160ff021916908315150217905550565b60026008541415611e04576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dfb90614c14565b60405180910390fd5b6002600881905550601660009054906101000a900460ff16611e5b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e5290614c80565b60405180910390fd5b60125481601760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611ea9919061485a565b1115611eea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee190614d12565b60405180910390fd5b60135481611ef6610ee7565b611f00919061485a565b1115611f41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f3890614a16565b60405180910390fd5b3481601154611f509190614d32565b1115611f91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f8890614dd8565b60405180910390fd5b611f9b3382612dae565b80601760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611fea919061485a565b92505081905550600160088190555050565b612004610af6565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612069576040517fb06307db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060076000612076610af6565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16612123610af6565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516121689190613e00565b60405180910390a35050565b601660019054906101000a900460ff1681565b60176020528060005260406000206000915090505481565b6121aa8484846128f8565b6121c98373ffffffffffffffffffffffffffffffffffffffff166131a7565b80156121de57506121dc848484846131ba565b155b15612215576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000612225610ee7565b905090565b60606122358261330b565b6040516020016122459190614e80565b6040516020818303038152906040529050919050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b601960009054906101000a900460ff1681565b60135481565b6000600f60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600b54905090565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b601660009054906101000a900460ff1681565b6123bf610af6565b73ffffffffffffffffffffffffffffffffffffffff166123dd611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614612433576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161242a90614718565b60405180910390fd5b601660019054906101000a900460ff1615601660016101000a81548160ff0219169083151502179055507f1727dc7b28fffc84b95ca0e64637ec1614ea28c6bc7e9efa20b6df6b2e65fe87601660019054906101000a900460ff1660405161249b9190613e00565b60405180910390a1565b6124ad610af6565b73ffffffffffffffffffffffffffffffffffffffff166124cb611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614612521576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161251890614718565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612591576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161258890614f14565b60405180910390fd5b61259a816130e1565b50565b6125a5610af6565b73ffffffffffffffffffffffffffffffffffffffff166125c3611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614612619576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161261090614718565b60405180910390fd5b8060118190555050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60008161269861278d565b111580156126a7575060005482105b80156126d4575060046000838152602001908152602001600020600001601c9054906101000a900460ff16155b9050919050565b826006600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b60006001905090565b600081600a54600c60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054856127e79190614d32565b6127f19190614f63565b6127fb9190614f94565b90509392505050565b80471015612847576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161283e90615014565b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405161286d90615065565b60006040518083038185875af1925050503d80600081146128aa576040519150601f19603f3d011682016040523d82523d6000602084013e6128af565b606091505b50509050806128f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128ea906150ec565b60405180910390fd5b505050565b600061290382612e52565b90508373ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161461296e576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008473ffffffffffffffffffffffffffffffffffffffff1661298f610af6565b73ffffffffffffffffffffffffffffffffffffffff1614806129be57506129bd856129b8610af6565b612310565b5b80612a0357506129cc610af6565b73ffffffffffffffffffffffffffffffffffffffff166129eb84610d60565b73ffffffffffffffffffffffffffffffffffffffff16145b905080612a3c576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415612aa3576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ab085858560016133aa565b612abc600084876126db565b6001600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a900467ffffffffffffffff160392506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506001600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a900467ffffffffffffffff160192506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506000600460008581526020019081526020016000209050848160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550428160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060006001850190506000600460008381526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415612d3c576000548214612d3b57878160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555084602001518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b5b505050828473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4612da785858560016133b0565b5050505050565b612dc88282604051806020016040528060008152506133b6565b5050565b612e4d8363a9059cbb60e01b8484604051602401612deb929190613d23565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506133c8565b505050565b612e5a613c69565b600082905080612e6861278d565b11158015612e77575060005481105b156130aa576000600460008381526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815260200160008201601c9054906101000a900460ff161515151581525050905080604001516130a857600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff1614612f8c5780925050506130dc565b5b6001156130a757818060019003925050600460008381526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815260200160008201601c9054906101000a900460ff1615151515815250509050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16146130a25780925050506130dc565b612f8d565b5b505b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080823b905060008111915050919050565b60008373ffffffffffffffffffffffffffffffffffffffff1663150b7a026131e0610af6565b8786866040518563ffffffff1660e01b81526004016132029493929190615161565b6020604051808303816000875af192505050801561323e57506040513d601f19601f8201168201806040525081019061323b91906151c2565b60015b6132b8573d806000811461326e576040519150601f19603f3d011682016040523d82523d6000602084013e613273565b606091505b506000815114156132b0576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b60606133168261268d565b61334c576040517fa14c4b5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061335661348f565b905060008151141561337757604051806020016040528060008152506133a2565b8061338184613521565b6040516020016133929291906151ef565b6040516020818303038152906040525b915050919050565b50505050565b50505050565b6133c38383836001613682565b505050565b600061342a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613a509092919063ffffffff16565b905060008151111561348a578080602001905181019061344a9190615228565b613489576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613480906152c7565b60405180910390fd5b5b505050565b60606018805461349e90614767565b80601f01602080910402602001604051908101604052809291908181526020018280546134ca90614767565b80156135175780601f106134ec57610100808354040283529160200191613517565b820191906000526020600020905b8154815290600101906020018083116134fa57829003601f168201915b5050505050905090565b60606000821415613569576040518060400160405280600181526020017f3000000000000000000000000000000000000000000000000000000000000000815250905061367d565b600082905060005b6000821461359b57808061358490614b7f565b915050600a826135949190614f63565b9150613571565b60008167ffffffffffffffff8111156135b7576135b6614117565b5b6040519080825280601f01601f1916602001820160405280156135e95781602001600182028036833780820191505090505b5090505b60008514613676576001826136029190614f94565b9150600a8561361191906152e7565b603061361d919061485a565b60f81b81838151811061363357613632614ae4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a8561366f9190614f63565b94506135ed565b8093505050505b919050565b600080549050600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156136ef576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084141561372a576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61373760008683876133aa565b83600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a900467ffffffffffffffff160192506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555083600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160088282829054906101000a900467ffffffffffffffff160192506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550846004600083815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550426004600083815260200190815260200160002060000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060008190506000858201905083801561390157506139008773ffffffffffffffffffffffffffffffffffffffff166131a7565b5b156139c7575b818773ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a461397660008884806001019550886131ba565b6139ac576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808214156139075782600054146139c257600080fd5b613a33565b5b818060010192508773ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4808214156139c8575b816000819055505050613a4960008683876133b0565b5050505050565b6060613a5f8484600085613a68565b90509392505050565b606082471015613aad576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613aa49061538a565b60405180910390fd5b613ab6856131a7565b613af5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613aec906153f6565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613b1e9190615447565b60006040518083038185875af1925050503d8060008114613b5b576040519150601f19603f3d011682016040523d82523d6000602084013e613b60565b606091505b5091509150613b70828286613b7c565b92505050949350505050565b60608315613b8c57829050613bdc565b600083511115613b9f5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613bd39190613eb4565b60405180910390fd5b9392505050565b828054613bef90614767565b90600052602060002090601f016020900481019282613c115760008555613c58565b82601f10613c2a57805160ff1916838001178555613c58565b82800160010185558215613c58579182015b82811115613c57578251825591602001919060010190613c3c565b5b509050613c659190613cac565b5090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff1681526020016000151581525090565b5b80821115613cc5576000816000905550600101613cad565b5090565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613cf482613cc9565b9050919050565b613d0481613ce9565b82525050565b6000819050919050565b613d1d81613d0a565b82525050565b6000604082019050613d386000830185613cfb565b613d456020830184613d14565b9392505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613d9581613d60565b8114613da057600080fd5b50565b600081359050613db281613d8c565b92915050565b600060208284031215613dce57613dcd613d56565b5b6000613ddc84828501613da3565b91505092915050565b60008115159050919050565b613dfa81613de5565b82525050565b6000602082019050613e156000830184613df1565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613e55578082015181840152602081019050613e3a565b83811115613e64576000848401525b50505050565b6000601f19601f8301169050919050565b6000613e8682613e1b565b613e908185613e26565b9350613ea0818560208601613e37565b613ea981613e6a565b840191505092915050565b60006020820190508181036000830152613ece8184613e7b565b905092915050565b613edf81613d0a565b8114613eea57600080fd5b50565b600081359050613efc81613ed6565b92915050565b600060208284031215613f1857613f17613d56565b5b6000613f2684828501613eed565b91505092915050565b6000602082019050613f446000830184613cfb565b92915050565b613f5381613ce9565b8114613f5e57600080fd5b50565b600081359050613f7081613f4a565b92915050565b60008060408385031215613f8d57613f8c613d56565b5b6000613f9b85828601613f61565b9250506020613fac85828601613eed565b9150509250929050565b6000602082019050613fcb6000830184613d14565b92915050565b6000613fdc82613cc9565b9050919050565b613fec81613fd1565b8114613ff757600080fd5b50565b60008135905061400981613fe3565b92915050565b60006020828403121561402557614024613d56565b5b600061403384828501613ffa565b91505092915050565b60008060006060848603121561405557614054613d56565b5b600061406386828701613f61565b935050602061407486828701613f61565b925050604061408586828701613eed565b9150509250925092565b600061409a82613ce9565b9050919050565b6140aa8161408f565b81146140b557600080fd5b50565b6000813590506140c7816140a1565b92915050565b600080604083850312156140e4576140e3613d56565b5b60006140f2858286016140b8565b925050602061410385828601613f61565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61414f82613e6a565b810181811067ffffffffffffffff8211171561416e5761416d614117565b5b80604052505050565b6000614181613d4c565b905061418d8282614146565b919050565b600067ffffffffffffffff8211156141ad576141ac614117565b5b6141b682613e6a565b9050602081019050919050565b82818337600083830152505050565b60006141e56141e084614192565b614177565b90508281526020810184848401111561420157614200614112565b5b61420c8482856141c3565b509392505050565b600082601f8301126142295761422861410d565b5b81356142398482602086016141d2565b91505092915050565b60006020828403121561425857614257613d56565b5b600082013567ffffffffffffffff81111561427657614275613d5b565b5b61428284828501614214565b91505092915050565b6000602082840312156142a1576142a0613d56565b5b60006142af84828501613f61565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6142ed81613d0a565b82525050565b60006142ff83836142e4565b60208301905092915050565b6000602082019050919050565b6000614323826142b8565b61432d81856142c3565b9350614338836142d4565b8060005b8381101561436957815161435088826142f3565b975061435b8361430b565b92505060018101905061433c565b5085935050505092915050565b600060208201905081810360008301526143908184614318565b905092915050565b600080fd5b600080fd5b60008083601f8401126143b8576143b761410d565b5b8235905067ffffffffffffffff8111156143d5576143d4614398565b5b6020830191508360208202830111156143f1576143f061439d565b5b9250929050565b60008083601f84011261440e5761440d61410d565b5b8235905067ffffffffffffffff81111561442b5761442a614398565b5b6020830191508360208202830111156144475761444661439d565b5b9250929050565b6000806000806040858703121561446857614467613d56565b5b600085013567ffffffffffffffff81111561448657614485613d5b565b5b614492878288016143a2565b9450945050602085013567ffffffffffffffff8111156144b5576144b4613d5b565b5b6144c1878288016143f8565b925092505092959194509250565b6144d881613de5565b81146144e357600080fd5b50565b6000813590506144f5816144cf565b92915050565b6000806040838503121561451257614511613d56565b5b600061452085828601613f61565b9250506020614531858286016144e6565b9150509250929050565b600067ffffffffffffffff82111561455657614555614117565b5b61455f82613e6a565b9050602081019050919050565b600061457f61457a8461453b565b614177565b90508281526020810184848401111561459b5761459a614112565b5b6145a68482856141c3565b509392505050565b600082601f8301126145c3576145c261410d565b5b81356145d384826020860161456c565b91505092915050565b600080600080608085870312156145f6576145f5613d56565b5b600061460487828801613f61565b945050602061461587828801613f61565b935050604061462687828801613eed565b925050606085013567ffffffffffffffff81111561464757614646613d5b565b5b614653878288016145ae565b91505092959194509250565b60006020828403121561467557614674613d56565b5b6000614683848285016140b8565b91505092915050565b600080604083850312156146a3576146a2613d56565b5b60006146b185828601613f61565b92505060206146c285828601613f61565b9150509250929050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614702602083613e26565b915061470d826146cc565b602082019050919050565b60006020820190508181036000830152614731816146f5565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061477f57607f821691505b6020821081141561479357614792614738565b5b50919050565b7f5061796d656e7453706c69747465723a206163636f756e7420686173206e6f2060008201527f7368617265730000000000000000000000000000000000000000000000000000602082015250565b60006147f5602683613e26565b915061480082614799565b604082019050919050565b60006020820190508181036000830152614824816147e8565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061486582613d0a565b915061487083613d0a565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156148a5576148a461482b565b5b828201905092915050565b7f5061796d656e7453706c69747465723a206163636f756e74206973206e6f742060008201527f647565207061796d656e74000000000000000000000000000000000000000000602082015250565b600061490c602b83613e26565b9150614917826148b0565b604082019050919050565b6000602082019050818103600083015261493b816148ff565b9050919050565b6000819050919050565b600061496761496261495d84613cc9565b614942565b613cc9565b9050919050565b60006149798261494c565b9050919050565b600061498b8261496e565b9050919050565b61499b81614980565b82525050565b60006040820190506149b66000830185614992565b6149c36020830184613d14565b9392505050565b7f534f4c44204f5554000000000000000000000000000000000000000000000000600082015250565b6000614a00600883613e26565b9150614a0b826149ca565b602082019050919050565b60006020820190508181036000830152614a2f816149f3565b9050919050565b600081519050614a4581613ed6565b92915050565b600060208284031215614a6157614a60613d56565b5b6000614a6f84828501614a36565b91505092915050565b7f4d455441444154415f4c4f434b45440000000000000000000000000000000000600082015250565b6000614aae600f83613e26565b9150614ab982614a78565b602082019050919050565b60006020820190508181036000830152614add81614aa1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f41495244524f50204e4f54204143544956450000000000000000000000000000600082015250565b6000614b49601283613e26565b9150614b5482614b13565b602082019050919050565b60006020820190508181036000830152614b7881614b3c565b9050919050565b6000614b8a82613d0a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614bbd57614bbc61482b565b5b600182019050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000614bfe601f83613e26565b9150614c0982614bc8565b602082019050919050565b60006020820190508181036000830152614c2d81614bf1565b9050919050565b7f53414c4520494e41435449564500000000000000000000000000000000000000600082015250565b6000614c6a600d83613e26565b9150614c7582614c34565b602082019050919050565b60006020820190508181036000830152614c9981614c5d565b9050919050565b7f7468697320776f756c6420657863656564206d696e74206d617820616c6c6f7760008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000614cfc602483613e26565b9150614d0782614ca0565b604082019050919050565b60006020820190508181036000830152614d2b81614cef565b9050919050565b6000614d3d82613d0a565b9150614d4883613d0a565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614d8157614d8061482b565b5b828202905092915050565b7f494e434f52524543542045544845522056414c55450000000000000000000000600082015250565b6000614dc2601583613e26565b9150614dcd82614d8c565b602082019050919050565b60006020820190508181036000830152614df181614db5565b9050919050565b600081905092915050565b6000614e0e82613e1b565b614e188185614df8565b9350614e28818560208601613e37565b80840191505092915050565b7f2e6a736f6e000000000000000000000000000000000000000000000000000000600082015250565b6000614e6a600583614df8565b9150614e7582614e34565b600582019050919050565b6000614e8c8284614e03565b9150614e9782614e5d565b915081905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614efe602683613e26565b9150614f0982614ea2565b604082019050919050565b60006020820190508181036000830152614f2d81614ef1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614f6e82613d0a565b9150614f7983613d0a565b925082614f8957614f88614f34565b5b828204905092915050565b6000614f9f82613d0a565b9150614faa83613d0a565b925082821015614fbd57614fbc61482b565b5b828203905092915050565b7f416464726573733a20696e73756666696369656e742062616c616e6365000000600082015250565b6000614ffe601d83613e26565b915061500982614fc8565b602082019050919050565b6000602082019050818103600083015261502d81614ff1565b9050919050565b600081905092915050565b50565b600061504f600083615034565b915061505a8261503f565b600082019050919050565b600061507082615042565b9150819050919050565b7f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260008201527f6563697069656e74206d61792068617665207265766572746564000000000000602082015250565b60006150d6603a83613e26565b91506150e18261507a565b604082019050919050565b60006020820190508181036000830152615105816150c9565b9050919050565b600081519050919050565b600082825260208201905092915050565b60006151338261510c565b61513d8185615117565b935061514d818560208601613e37565b61515681613e6a565b840191505092915050565b60006080820190506151766000830187613cfb565b6151836020830186613cfb565b6151906040830185613d14565b81810360608301526151a28184615128565b905095945050505050565b6000815190506151bc81613d8c565b92915050565b6000602082840312156151d8576151d7613d56565b5b60006151e6848285016151ad565b91505092915050565b60006151fb8285614e03565b91506152078284614e03565b91508190509392505050565b600081519050615222816144cf565b92915050565b60006020828403121561523e5761523d613d56565b5b600061524c84828501615213565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b60006152b1602a83613e26565b91506152bc82615255565b604082019050919050565b600060208201905081810360008301526152e0816152a4565b9050919050565b60006152f282613d0a565b91506152fd83613d0a565b92508261530d5761530c614f34565b5b828206905092915050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b6000615374602683613e26565b915061537f82615318565b604082019050919050565b600060208201905081810360008301526153a381615367565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b60006153e0601d83613e26565b91506153eb826153aa565b602082019050919050565b6000602082019050818103600083015261540f816153d3565b9050919050565b60006154218261510c565b61542b8185615034565b935061543b818560208601613e37565b80840191505092915050565b60006154538284615416565b91508190509291505056fea26469706673582212200a61d2076ec37ff00cda8bb3d448ff38bdc17c1ab6dde57df6e6acaf9e8a7be864736f6c634300080a003368747470733a2f2f6170656c69717569642e6d7970696e6174612e636c6f75642f697066732f516d5054384b447477654e46783145717446646159686b727641476541476f593175624347784b783873704475722f

Deployed Bytecode

0x6080604052600436106102815760003560e01c80638b83209b1161014f578063c4e41b22116100c1578063e33b7de31161007a578063e33b7de3146109fa578063e985e9c514610a25578063eb8d244414610a62578063ef6d492714610a8d578063f2fde38b14610aa4578063f4a0a52814610acd576102c8565b8063c4e41b22146108c2578063c87b56dd146108ed578063ce7c2ac21461092a578063cf30901214610967578063d5abeb0114610992578063d79779b2146109bd576102c8565b8063989bdbb611610113578063989bdbb6146107d5578063a0712d68146107ec578063a22cb46514610808578063aa3f395514610831578063ab2fdb0c1461085c578063b88d4fde14610899576102c8565b80638b83209b146106da5780638da5cb5b1461071757806395d89b4114610742578063977b055b1461076d5780639852595c14610798576102c8565b806342842e0e116101f35780636352211e116101ac5780636352211e146105cc5780636673c4c2146106095780636817c76c1461063257806370a082311461065d578063711897421461069a578063715018a6146106c3576102c8565b806342842e0e146104d4578063484b973c146104fd57806348b75044146105265780634e71d92d1461054f57806355f804b314610566578063627fdeab1461058f576102c8565b806318160ddd1161024557806318160ddd146103b257806319165587146103dd57806323b872dd14610406578063283248be1461042f5780633a98ef391461046c578063406072a914610497576102c8565b806301ffc9a7146102cd578063049c5c491461030a57806306fdde0314610321578063081812fc1461034c578063095ea7b314610389576102c8565b366102c8577f6ef95f06320e7a25a04a175ca677b7052bdd97131872c2192525a629f51be7706102af610af6565b346040516102be929190613d23565b60405180910390a1005b600080fd5b3480156102d957600080fd5b506102f460048036038101906102ef9190613db8565b610afe565b6040516103019190613e00565b60405180910390f35b34801561031657600080fd5b5061031f610be0565b005b34801561032d57600080fd5b50610336610cce565b6040516103439190613eb4565b60405180910390f35b34801561035857600080fd5b50610373600480360381019061036e9190613f02565b610d60565b6040516103809190613f2f565b60405180910390f35b34801561039557600080fd5b506103b060048036038101906103ab9190613f76565b610ddc565b005b3480156103be57600080fd5b506103c7610ee7565b6040516103d49190613fb6565b60405180910390f35b3480156103e957600080fd5b5061040460048036038101906103ff919061400f565b610efe565b005b34801561041257600080fd5b5061042d6004803603810190610428919061403c565b6110a9565b005b34801561043b57600080fd5b5061045660048036038101906104519190613f02565b6110b9565b6040516104639190613f2f565b60405180910390f35b34801561047857600080fd5b506104816110f8565b60405161048e9190613fb6565b60405180910390f35b3480156104a357600080fd5b506104be60048036038101906104b991906140cd565b611102565b6040516104cb9190613fb6565b60405180910390f35b3480156104e057600080fd5b506104fb60048036038101906104f6919061403c565b611189565b005b34801561050957600080fd5b50610524600480360381019061051f9190613f76565b6111a9565b005b34801561053257600080fd5b5061054d600480360381019061054891906140cd565b61128a565b005b34801561055b57600080fd5b50610564611543565b005b34801561057257600080fd5b5061058d60048036038101906105889190614242565b61154e565b005b34801561059b57600080fd5b506105b660048036038101906105b1919061428b565b611634565b6040516105c39190614376565b60405180910390f35b3480156105d857600080fd5b506105f360048036038101906105ee9190613f02565b61182b565b6040516106009190613f2f565b60405180910390f35b34801561061557600080fd5b50610630600480360381019061062b919061444e565b611841565b005b34801561063e57600080fd5b506106476119ee565b6040516106549190613fb6565b60405180910390f35b34801561066957600080fd5b50610684600480360381019061067f919061428b565b6119f4565b6040516106919190613fb6565b60405180910390f35b3480156106a657600080fd5b506106c160048036038101906106bc9190613f02565b611ac4565b005b3480156106cf57600080fd5b506106d8611b4a565b005b3480156106e657600080fd5b5061070160048036038101906106fc9190613f02565b611bd2565b60405161070e9190613f2f565b60405180910390f35b34801561072357600080fd5b5061072c611c1a565b6040516107399190613f2f565b60405180910390f35b34801561074e57600080fd5b50610757611c44565b6040516107649190613eb4565b60405180910390f35b34801561077957600080fd5b50610782611cd6565b60405161078f9190613fb6565b60405180910390f35b3480156107a457600080fd5b506107bf60048036038101906107ba919061428b565b611cdc565b6040516107cc9190613fb6565b60405180910390f35b3480156107e157600080fd5b506107ea611d25565b005b61080660048036038101906108019190613f02565b611dbe565b005b34801561081457600080fd5b5061082f600480360381019061082a91906144fb565b611ffc565b005b34801561083d57600080fd5b50610846612174565b6040516108539190613e00565b60405180910390f35b34801561086857600080fd5b50610883600480360381019061087e919061428b565b612187565b6040516108909190613fb6565b60405180910390f35b3480156108a557600080fd5b506108c060048036038101906108bb91906145dc565b61219f565b005b3480156108ce57600080fd5b506108d761221b565b6040516108e49190613fb6565b60405180910390f35b3480156108f957600080fd5b50610914600480360381019061090f9190613f02565b61222a565b6040516109219190613eb4565b60405180910390f35b34801561093657600080fd5b50610951600480360381019061094c919061428b565b61225b565b60405161095e9190613fb6565b60405180910390f35b34801561097357600080fd5b5061097c6122a4565b6040516109899190613e00565b60405180910390f35b34801561099e57600080fd5b506109a76122b7565b6040516109b49190613fb6565b60405180910390f35b3480156109c957600080fd5b506109e460048036038101906109df919061465f565b6122bd565b6040516109f19190613fb6565b60405180910390f35b348015610a0657600080fd5b50610a0f612306565b604051610a1c9190613fb6565b60405180910390f35b348015610a3157600080fd5b50610a4c6004803603810190610a47919061468c565b612310565b604051610a599190613e00565b60405180910390f35b348015610a6e57600080fd5b50610a776123a4565b604051610a849190613e00565b60405180910390f35b348015610a9957600080fd5b50610aa26123b7565b005b348015610ab057600080fd5b50610acb6004803603810190610ac6919061428b565b6124a5565b005b348015610ad957600080fd5b50610af46004803603810190610aef9190613f02565b61259d565b005b600033905090565b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610bc957507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610bd95750610bd882612623565b5b9050919050565b610be8610af6565b73ffffffffffffffffffffffffffffffffffffffff16610c06611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614610c5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5390614718565b60405180910390fd5b601660009054906101000a900460ff1615601660006101000a81548160ff0219169083151502179055507f58655b75d3df612fe99ead00dbf0812d415d35078fe06217a94c0818bb13967f601660009054906101000a900460ff16604051610cc49190613e00565b60405180910390a1565b606060028054610cdd90614767565b80601f0160208091040260200160405190810160405280929190818152602001828054610d0990614767565b8015610d565780601f10610d2b57610100808354040283529160200191610d56565b820191906000526020600020905b815481529060010190602001808311610d3957829003601f168201915b5050505050905090565b6000610d6b8261268d565b610da1576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000610de78261182b565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610e4f576040517f943f7b8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610e6e610af6565b73ffffffffffffffffffffffffffffffffffffffff1614158015610ea05750610e9e81610e99610af6565b612310565b155b15610ed7576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ee28383836126db565b505050565b6000610ef161278d565b6001546000540303905090565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411610f80576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f779061480b565b60405180910390fd5b6000610f8a612306565b47610f95919061485a565b90506000610fac8383610fa786611cdc565b612796565b90506000811415610ff2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe990614922565b60405180910390fd5b80600d60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611041919061485a565b9250508190555080600b600082825461105a919061485a565b9250508190555061106b8382612804565b7fdf20fd1e76bc69d672e4814fafb2c449bba3a5369d8359adf9e05e6fde87b056838260405161109c9291906149a1565b60405180910390a1505050565b6110b48383836128f8565b505050565b601481815481106110c957600080fd5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600a54905090565b6000601060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6111a48383836040518060200160405280600081525061219f565b505050565b6111b1610af6565b73ffffffffffffffffffffffffffffffffffffffff166111cf611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614611225576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121c90614718565b60405180910390fd5b60135481611231610ee7565b61123b919061485a565b111561127c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161127390614a16565b60405180910390fd5b6112868282612dae565b5050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541161130c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113039061480b565b60405180910390fd5b6000611317836122bd565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016113509190613f2f565b602060405180830381865afa15801561136d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113919190614a4b565b61139b919061485a565b905060006113b383836113ae8787611102565b612796565b905060008114156113f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113f090614922565b60405180910390fd5b80601060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611485919061485a565b9250508190555080600f60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546114db919061485a565b925050819055506114ed848483612dcc565b8373ffffffffffffffffffffffffffffffffffffffff167f3be5b7a71e84ed12875d241991c70855ac5817d847039e17a9d895c1ceb0f18a8483604051611535929190613d23565b60405180910390a250505050565b61154c33610efe565b565b611556610af6565b73ffffffffffffffffffffffffffffffffffffffff16611574611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146115ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115c190614718565b60405180910390fd5b601960009054906101000a900460ff161561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161161190614ac4565b60405180910390fd5b8060189080519060200190611630929190613be3565b5050565b60606000611641836119f4565b67ffffffffffffffff81111561165a57611659614117565b5b6040519080825280602002602001820160405280156116885781602001602082028036833780820191505090505b50905060008054905060008060005b8381101561181e576000600460008381526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815260200160008201601c9054906101000a900460ff16151515158152505090508060400151156117745750611811565b600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16146117b457806000015192505b8773ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561180f578186858060010196508151811061180257611801614ae4565b5b6020026020010181815250505b505b8080600101915050611697565b5083945050505050919050565b600061183682612e52565b600001519050919050565b611849610af6565b73ffffffffffffffffffffffffffffffffffffffff16611867611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146118bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118b490614718565b60405180910390fd5b601660019054906101000a900460ff1661190c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161190390614b5f565b60405180910390fd5b60005b828290508110156119e7576013548585838181106119305761192f614ae4565b5b9050602002013561193f610ee7565b611949919061485a565b111561198a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161198190614a16565b60405180910390fd5b6119d48383838181106119a05761199f614ae4565b5b90506020020160208101906119b5919061428b565b8686848181106119c8576119c7614ae4565b5b90506020020135612dae565b80806119df90614b7f565b91505061190f565b5050505050565b60115481565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611a5c576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900467ffffffffffffffff1667ffffffffffffffff169050919050565b611acc610af6565b73ffffffffffffffffffffffffffffffffffffffff16611aea611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614611b40576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b3790614718565b60405180910390fd5b8060128190555050565b611b52610af6565b73ffffffffffffffffffffffffffffffffffffffff16611b70611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614611bc6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bbd90614718565b60405180910390fd5b611bd060006130e1565b565b6000600e8281548110611be857611be7614ae4565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060038054611c5390614767565b80601f0160208091040260200160405190810160405280929190818152602001828054611c7f90614767565b8015611ccc5780601f10611ca157610100808354040283529160200191611ccc565b820191906000526020600020905b815481529060010190602001808311611caf57829003601f168201915b5050505050905090565b60125481565b6000600d60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b611d2d610af6565b73ffffffffffffffffffffffffffffffffffffffff16611d4b611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614611da1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d9890614718565b60405180910390fd5b6001601960006101000a81548160ff021916908315150217905550565b60026008541415611e04576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dfb90614c14565b60405180910390fd5b6002600881905550601660009054906101000a900460ff16611e5b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e5290614c80565b60405180910390fd5b60125481601760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611ea9919061485a565b1115611eea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee190614d12565b60405180910390fd5b60135481611ef6610ee7565b611f00919061485a565b1115611f41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f3890614a16565b60405180910390fd5b3481601154611f509190614d32565b1115611f91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f8890614dd8565b60405180910390fd5b611f9b3382612dae565b80601760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611fea919061485a565b92505081905550600160088190555050565b612004610af6565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612069576040517fb06307db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060076000612076610af6565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16612123610af6565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516121689190613e00565b60405180910390a35050565b601660019054906101000a900460ff1681565b60176020528060005260406000206000915090505481565b6121aa8484846128f8565b6121c98373ffffffffffffffffffffffffffffffffffffffff166131a7565b80156121de57506121dc848484846131ba565b155b15612215576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000612225610ee7565b905090565b60606122358261330b565b6040516020016122459190614e80565b6040516020818303038152906040529050919050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b601960009054906101000a900460ff1681565b60135481565b6000600f60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600b54905090565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b601660009054906101000a900460ff1681565b6123bf610af6565b73ffffffffffffffffffffffffffffffffffffffff166123dd611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614612433576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161242a90614718565b60405180910390fd5b601660019054906101000a900460ff1615601660016101000a81548160ff0219169083151502179055507f1727dc7b28fffc84b95ca0e64637ec1614ea28c6bc7e9efa20b6df6b2e65fe87601660019054906101000a900460ff1660405161249b9190613e00565b60405180910390a1565b6124ad610af6565b73ffffffffffffffffffffffffffffffffffffffff166124cb611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614612521576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161251890614718565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612591576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161258890614f14565b60405180910390fd5b61259a816130e1565b50565b6125a5610af6565b73ffffffffffffffffffffffffffffffffffffffff166125c3611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614612619576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161261090614718565b60405180910390fd5b8060118190555050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60008161269861278d565b111580156126a7575060005482105b80156126d4575060046000838152602001908152602001600020600001601c9054906101000a900460ff16155b9050919050565b826006600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b60006001905090565b600081600a54600c60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054856127e79190614d32565b6127f19190614f63565b6127fb9190614f94565b90509392505050565b80471015612847576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161283e90615014565b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405161286d90615065565b60006040518083038185875af1925050503d80600081146128aa576040519150601f19603f3d011682016040523d82523d6000602084013e6128af565b606091505b50509050806128f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128ea906150ec565b60405180910390fd5b505050565b600061290382612e52565b90508373ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161461296e576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008473ffffffffffffffffffffffffffffffffffffffff1661298f610af6565b73ffffffffffffffffffffffffffffffffffffffff1614806129be57506129bd856129b8610af6565b612310565b5b80612a0357506129cc610af6565b73ffffffffffffffffffffffffffffffffffffffff166129eb84610d60565b73ffffffffffffffffffffffffffffffffffffffff16145b905080612a3c576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415612aa3576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ab085858560016133aa565b612abc600084876126db565b6001600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a900467ffffffffffffffff160392506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506001600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a900467ffffffffffffffff160192506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506000600460008581526020019081526020016000209050848160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550428160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060006001850190506000600460008381526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415612d3c576000548214612d3b57878160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555084602001518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b5b505050828473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4612da785858560016133b0565b5050505050565b612dc88282604051806020016040528060008152506133b6565b5050565b612e4d8363a9059cbb60e01b8484604051602401612deb929190613d23565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506133c8565b505050565b612e5a613c69565b600082905080612e6861278d565b11158015612e77575060005481105b156130aa576000600460008381526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815260200160008201601c9054906101000a900460ff161515151581525050905080604001516130a857600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff1614612f8c5780925050506130dc565b5b6001156130a757818060019003925050600460008381526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815260200160008201601c9054906101000a900460ff1615151515815250509050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16146130a25780925050506130dc565b612f8d565b5b505b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080823b905060008111915050919050565b60008373ffffffffffffffffffffffffffffffffffffffff1663150b7a026131e0610af6565b8786866040518563ffffffff1660e01b81526004016132029493929190615161565b6020604051808303816000875af192505050801561323e57506040513d601f19601f8201168201806040525081019061323b91906151c2565b60015b6132b8573d806000811461326e576040519150601f19603f3d011682016040523d82523d6000602084013e613273565b606091505b506000815114156132b0576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b60606133168261268d565b61334c576040517fa14c4b5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061335661348f565b905060008151141561337757604051806020016040528060008152506133a2565b8061338184613521565b6040516020016133929291906151ef565b6040516020818303038152906040525b915050919050565b50505050565b50505050565b6133c38383836001613682565b505050565b600061342a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613a509092919063ffffffff16565b905060008151111561348a578080602001905181019061344a9190615228565b613489576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613480906152c7565b60405180910390fd5b5b505050565b60606018805461349e90614767565b80601f01602080910402602001604051908101604052809291908181526020018280546134ca90614767565b80156135175780601f106134ec57610100808354040283529160200191613517565b820191906000526020600020905b8154815290600101906020018083116134fa57829003601f168201915b5050505050905090565b60606000821415613569576040518060400160405280600181526020017f3000000000000000000000000000000000000000000000000000000000000000815250905061367d565b600082905060005b6000821461359b57808061358490614b7f565b915050600a826135949190614f63565b9150613571565b60008167ffffffffffffffff8111156135b7576135b6614117565b5b6040519080825280601f01601f1916602001820160405280156135e95781602001600182028036833780820191505090505b5090505b60008514613676576001826136029190614f94565b9150600a8561361191906152e7565b603061361d919061485a565b60f81b81838151811061363357613632614ae4565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a8561366f9190614f63565b94506135ed565b8093505050505b919050565b600080549050600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156136ef576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084141561372a576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61373760008683876133aa565b83600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a900467ffffffffffffffff160192506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555083600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160088282829054906101000a900467ffffffffffffffff160192506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550846004600083815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550426004600083815260200190815260200160002060000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060008190506000858201905083801561390157506139008773ffffffffffffffffffffffffffffffffffffffff166131a7565b5b156139c7575b818773ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a461397660008884806001019550886131ba565b6139ac576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808214156139075782600054146139c257600080fd5b613a33565b5b818060010192508773ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4808214156139c8575b816000819055505050613a4960008683876133b0565b5050505050565b6060613a5f8484600085613a68565b90509392505050565b606082471015613aad576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613aa49061538a565b60405180910390fd5b613ab6856131a7565b613af5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613aec906153f6565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613b1e9190615447565b60006040518083038185875af1925050503d8060008114613b5b576040519150601f19603f3d011682016040523d82523d6000602084013e613b60565b606091505b5091509150613b70828286613b7c565b92505050949350505050565b60608315613b8c57829050613bdc565b600083511115613b9f5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613bd39190613eb4565b60405180910390fd5b9392505050565b828054613bef90614767565b90600052602060002090601f016020900481019282613c115760008555613c58565b82601f10613c2a57805160ff1916838001178555613c58565b82800160010185558215613c58579182015b82811115613c57578251825591602001919060010190613c3c565b5b509050613c659190613cac565b5090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff1681526020016000151581525090565b5b80821115613cc5576000816000905550600101613cad565b5090565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613cf482613cc9565b9050919050565b613d0481613ce9565b82525050565b6000819050919050565b613d1d81613d0a565b82525050565b6000604082019050613d386000830185613cfb565b613d456020830184613d14565b9392505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613d9581613d60565b8114613da057600080fd5b50565b600081359050613db281613d8c565b92915050565b600060208284031215613dce57613dcd613d56565b5b6000613ddc84828501613da3565b91505092915050565b60008115159050919050565b613dfa81613de5565b82525050565b6000602082019050613e156000830184613df1565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613e55578082015181840152602081019050613e3a565b83811115613e64576000848401525b50505050565b6000601f19601f8301169050919050565b6000613e8682613e1b565b613e908185613e26565b9350613ea0818560208601613e37565b613ea981613e6a565b840191505092915050565b60006020820190508181036000830152613ece8184613e7b565b905092915050565b613edf81613d0a565b8114613eea57600080fd5b50565b600081359050613efc81613ed6565b92915050565b600060208284031215613f1857613f17613d56565b5b6000613f2684828501613eed565b91505092915050565b6000602082019050613f446000830184613cfb565b92915050565b613f5381613ce9565b8114613f5e57600080fd5b50565b600081359050613f7081613f4a565b92915050565b60008060408385031215613f8d57613f8c613d56565b5b6000613f9b85828601613f61565b9250506020613fac85828601613eed565b9150509250929050565b6000602082019050613fcb6000830184613d14565b92915050565b6000613fdc82613cc9565b9050919050565b613fec81613fd1565b8114613ff757600080fd5b50565b60008135905061400981613fe3565b92915050565b60006020828403121561402557614024613d56565b5b600061403384828501613ffa565b91505092915050565b60008060006060848603121561405557614054613d56565b5b600061406386828701613f61565b935050602061407486828701613f61565b925050604061408586828701613eed565b9150509250925092565b600061409a82613ce9565b9050919050565b6140aa8161408f565b81146140b557600080fd5b50565b6000813590506140c7816140a1565b92915050565b600080604083850312156140e4576140e3613d56565b5b60006140f2858286016140b8565b925050602061410385828601613f61565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61414f82613e6a565b810181811067ffffffffffffffff8211171561416e5761416d614117565b5b80604052505050565b6000614181613d4c565b905061418d8282614146565b919050565b600067ffffffffffffffff8211156141ad576141ac614117565b5b6141b682613e6a565b9050602081019050919050565b82818337600083830152505050565b60006141e56141e084614192565b614177565b90508281526020810184848401111561420157614200614112565b5b61420c8482856141c3565b509392505050565b600082601f8301126142295761422861410d565b5b81356142398482602086016141d2565b91505092915050565b60006020828403121561425857614257613d56565b5b600082013567ffffffffffffffff81111561427657614275613d5b565b5b61428284828501614214565b91505092915050565b6000602082840312156142a1576142a0613d56565b5b60006142af84828501613f61565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6142ed81613d0a565b82525050565b60006142ff83836142e4565b60208301905092915050565b6000602082019050919050565b6000614323826142b8565b61432d81856142c3565b9350614338836142d4565b8060005b8381101561436957815161435088826142f3565b975061435b8361430b565b92505060018101905061433c565b5085935050505092915050565b600060208201905081810360008301526143908184614318565b905092915050565b600080fd5b600080fd5b60008083601f8401126143b8576143b761410d565b5b8235905067ffffffffffffffff8111156143d5576143d4614398565b5b6020830191508360208202830111156143f1576143f061439d565b5b9250929050565b60008083601f84011261440e5761440d61410d565b5b8235905067ffffffffffffffff81111561442b5761442a614398565b5b6020830191508360208202830111156144475761444661439d565b5b9250929050565b6000806000806040858703121561446857614467613d56565b5b600085013567ffffffffffffffff81111561448657614485613d5b565b5b614492878288016143a2565b9450945050602085013567ffffffffffffffff8111156144b5576144b4613d5b565b5b6144c1878288016143f8565b925092505092959194509250565b6144d881613de5565b81146144e357600080fd5b50565b6000813590506144f5816144cf565b92915050565b6000806040838503121561451257614511613d56565b5b600061452085828601613f61565b9250506020614531858286016144e6565b9150509250929050565b600067ffffffffffffffff82111561455657614555614117565b5b61455f82613e6a565b9050602081019050919050565b600061457f61457a8461453b565b614177565b90508281526020810184848401111561459b5761459a614112565b5b6145a68482856141c3565b509392505050565b600082601f8301126145c3576145c261410d565b5b81356145d384826020860161456c565b91505092915050565b600080600080608085870312156145f6576145f5613d56565b5b600061460487828801613f61565b945050602061461587828801613f61565b935050604061462687828801613eed565b925050606085013567ffffffffffffffff81111561464757614646613d5b565b5b614653878288016145ae565b91505092959194509250565b60006020828403121561467557614674613d56565b5b6000614683848285016140b8565b91505092915050565b600080604083850312156146a3576146a2613d56565b5b60006146b185828601613f61565b92505060206146c285828601613f61565b9150509250929050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614702602083613e26565b915061470d826146cc565b602082019050919050565b60006020820190508181036000830152614731816146f5565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061477f57607f821691505b6020821081141561479357614792614738565b5b50919050565b7f5061796d656e7453706c69747465723a206163636f756e7420686173206e6f2060008201527f7368617265730000000000000000000000000000000000000000000000000000602082015250565b60006147f5602683613e26565b915061480082614799565b604082019050919050565b60006020820190508181036000830152614824816147e8565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061486582613d0a565b915061487083613d0a565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156148a5576148a461482b565b5b828201905092915050565b7f5061796d656e7453706c69747465723a206163636f756e74206973206e6f742060008201527f647565207061796d656e74000000000000000000000000000000000000000000602082015250565b600061490c602b83613e26565b9150614917826148b0565b604082019050919050565b6000602082019050818103600083015261493b816148ff565b9050919050565b6000819050919050565b600061496761496261495d84613cc9565b614942565b613cc9565b9050919050565b60006149798261494c565b9050919050565b600061498b8261496e565b9050919050565b61499b81614980565b82525050565b60006040820190506149b66000830185614992565b6149c36020830184613d14565b9392505050565b7f534f4c44204f5554000000000000000000000000000000000000000000000000600082015250565b6000614a00600883613e26565b9150614a0b826149ca565b602082019050919050565b60006020820190508181036000830152614a2f816149f3565b9050919050565b600081519050614a4581613ed6565b92915050565b600060208284031215614a6157614a60613d56565b5b6000614a6f84828501614a36565b91505092915050565b7f4d455441444154415f4c4f434b45440000000000000000000000000000000000600082015250565b6000614aae600f83613e26565b9150614ab982614a78565b602082019050919050565b60006020820190508181036000830152614add81614aa1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f41495244524f50204e4f54204143544956450000000000000000000000000000600082015250565b6000614b49601283613e26565b9150614b5482614b13565b602082019050919050565b60006020820190508181036000830152614b7881614b3c565b9050919050565b6000614b8a82613d0a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614bbd57614bbc61482b565b5b600182019050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000614bfe601f83613e26565b9150614c0982614bc8565b602082019050919050565b60006020820190508181036000830152614c2d81614bf1565b9050919050565b7f53414c4520494e41435449564500000000000000000000000000000000000000600082015250565b6000614c6a600d83613e26565b9150614c7582614c34565b602082019050919050565b60006020820190508181036000830152614c9981614c5d565b9050919050565b7f7468697320776f756c6420657863656564206d696e74206d617820616c6c6f7760008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000614cfc602483613e26565b9150614d0782614ca0565b604082019050919050565b60006020820190508181036000830152614d2b81614cef565b9050919050565b6000614d3d82613d0a565b9150614d4883613d0a565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614d8157614d8061482b565b5b828202905092915050565b7f494e434f52524543542045544845522056414c55450000000000000000000000600082015250565b6000614dc2601583613e26565b9150614dcd82614d8c565b602082019050919050565b60006020820190508181036000830152614df181614db5565b9050919050565b600081905092915050565b6000614e0e82613e1b565b614e188185614df8565b9350614e28818560208601613e37565b80840191505092915050565b7f2e6a736f6e000000000000000000000000000000000000000000000000000000600082015250565b6000614e6a600583614df8565b9150614e7582614e34565b600582019050919050565b6000614e8c8284614e03565b9150614e9782614e5d565b915081905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614efe602683613e26565b9150614f0982614ea2565b604082019050919050565b60006020820190508181036000830152614f2d81614ef1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614f6e82613d0a565b9150614f7983613d0a565b925082614f8957614f88614f34565b5b828204905092915050565b6000614f9f82613d0a565b9150614faa83613d0a565b925082821015614fbd57614fbc61482b565b5b828203905092915050565b7f416464726573733a20696e73756666696369656e742062616c616e6365000000600082015250565b6000614ffe601d83613e26565b915061500982614fc8565b602082019050919050565b6000602082019050818103600083015261502d81614ff1565b9050919050565b600081905092915050565b50565b600061504f600083615034565b915061505a8261503f565b600082019050919050565b600061507082615042565b9150819050919050565b7f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260008201527f6563697069656e74206d61792068617665207265766572746564000000000000602082015250565b60006150d6603a83613e26565b91506150e18261507a565b604082019050919050565b60006020820190508181036000830152615105816150c9565b9050919050565b600081519050919050565b600082825260208201905092915050565b60006151338261510c565b61513d8185615117565b935061514d818560208601613e37565b61515681613e6a565b840191505092915050565b60006080820190506151766000830187613cfb565b6151836020830186613cfb565b6151906040830185613d14565b81810360608301526151a28184615128565b905095945050505050565b6000815190506151bc81613d8c565b92915050565b6000602082840312156151d8576151d7613d56565b5b60006151e6848285016151ad565b91505092915050565b60006151fb8285614e03565b91506152078284614e03565b91508190509392505050565b600081519050615222816144cf565b92915050565b60006020828403121561523e5761523d613d56565b5b600061524c84828501615213565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b60006152b1602a83613e26565b91506152bc82615255565b604082019050919050565b600060208201905081810360008301526152e0816152a4565b9050919050565b60006152f282613d0a565b91506152fd83613d0a565b92508261530d5761530c614f34565b5b828206905092915050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b6000615374602683613e26565b915061537f82615318565b604082019050919050565b600060208201905081810360008301526153a381615367565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b60006153e0601d83613e26565b91506153eb826153aa565b602082019050919050565b6000602082019050818103600083015261540f816153d3565b9050919050565b60006154218261510c565b61542b8185615034565b935061543b818560208601613e37565b80840191505092915050565b60006154538284615416565b91508190509291505056fea26469706673582212200a61d2076ec37ff00cda8bb3d448ff38bdc17c1ab6dde57df6e6acaf9e8a7be864736f6c634300080a0033

Deployed Bytecode Sourcemap

113305:4427:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;108687:40;108703:12;:10;:12::i;:::-;108717:9;108687:40;;;;;;;:::i;:::-;;;;;;;;113305:4427;;;;;79959:355;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115487:138;;;;;;;;;;;;;:::i;:::-;;83154:100;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;84754:245;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;84317:371;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;79208:303;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;110505:616;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;85742:170;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;113534:171;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;108818:91;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;109947:167;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;85983:185;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;114358:175;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;111389:704;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;116121:73;;;;;;;;;;;;;:::i;:::-;;117135:150;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;116202:820;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;82962:125;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;114541:418;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;113412:38;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;80378:206;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115904:110;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;69812:103;;;;;;;;;;;;;:::i;:::-;;110205:100;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;69161:87;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;83323:104;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;113457:30;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;109669:109;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;116022:75;;;;;;;;;;;;;:::i;:::-;;114967:512;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;85071:319;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;113816:34;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;113859:54;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;86239:406;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;117030:97;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;117415:205;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;109465:105;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;114065:18;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;113494:31;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;109255:119;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;109003:95;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;85461:214;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;113777:32;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;115633:153;;;;;;;;;;;;;:::i;:::-;;70070:238;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;115794:102;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;35332:98;35385:7;35412:10;35405:17;;35332:98;:::o;79959:355::-;80106:4;80163:25;80148:40;;;:11;:40;;;;:105;;;;80220:33;80205:48;;;:11;:48;;;;80148:105;:158;;;;80270:36;80294:11;80270:23;:36::i;:::-;80148:158;80128:178;;79959:355;;;:::o;115487:138::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;115561:12:::1;;;;;;;;;;;115560:13;115545:12;;:28;;;;;;;;;;;;;;;;;;115589;115604:12;;;;;;;;;;;115589:28;;;;;;:::i;:::-;;;;;;;;115487:138::o:0;83154:100::-;83208:13;83241:5;83234:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83154:100;:::o;84754:245::-;84858:7;84888:16;84896:7;84888;:16::i;:::-;84883:64;;84913:34;;;;;;;;;;;;;;84883:64;84967:15;:24;84983:7;84967:24;;;;;;;;;;;;;;;;;;;;;84960:31;;84754:245;;;:::o;84317:371::-;84390:13;84406:24;84422:7;84406:15;:24::i;:::-;84390:40;;84451:5;84445:11;;:2;:11;;;84441:48;;;84465:24;;;;;;;;;;;;;;84441:48;84522:5;84506:21;;:12;:10;:12::i;:::-;:21;;;;:63;;;;;84532:37;84549:5;84556:12;:10;:12::i;:::-;84532:16;:37::i;:::-;84531:38;84506:63;84502:138;;;84593:35;;;;;;;;;;;;;;84502:138;84652:28;84661:2;84665:7;84674:5;84652:8;:28::i;:::-;84379:309;84317:371;;:::o;79208:303::-;79252:7;79477:15;:13;:15::i;:::-;79462:12;;79446:13;;:28;:46;79439:53;;79208:303;:::o;110505:616::-;110600:1;110581:7;:16;110589:7;110581:16;;;;;;;;;;;;;;;;:20;110573:71;;;;;;;;;;;;:::i;:::-;;;;;;;;;110657:21;110705:15;:13;:15::i;:::-;110681:21;:39;;;;:::i;:::-;110657:63;;110731:15;110749:108;110779:7;110801:13;110829:17;110838:7;110829:8;:17::i;:::-;110749:15;:108::i;:::-;110731:126;;110889:1;110878:7;:12;;110870:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;110973:7;110951:9;:18;110961:7;110951:18;;;;;;;;;;;;;;;;:29;;;;;;;:::i;:::-;;;;;;;;111009:7;110991:14;;:25;;;;;;;:::i;:::-;;;;;;;;111029:35;111047:7;111056;111029:17;:35::i;:::-;111080:33;111096:7;111105;111080:33;;;;;;;:::i;:::-;;;;;;;;110562:559;;110505:616;:::o;85742:170::-;85876:28;85886:4;85892:2;85896:7;85876:9;:28::i;:::-;85742:170;;;:::o;113534:171::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;108818:91::-;108862:7;108889:12;;108882:19;;108818:91;:::o;109947:167::-;110044:7;110076:14;:21;110091:5;110076:21;;;;;;;;;;;;;;;:30;110098:7;110076:30;;;;;;;;;;;;;;;;110069:37;;109947:167;;;;:::o;85983:185::-;86121:39;86138:4;86144:2;86148:7;86121:39;;;;;;;;;;;;:16;:39::i;:::-;85983:185;;;:::o;114358:175::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;114470:9:::1;;114460:6;114444:13;:11;:13::i;:::-;:22;;;;:::i;:::-;:35;;114436:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;114503:22;114513:3;114518:6;114503:9;:22::i;:::-;114358:175:::0;;:::o;111389:704::-;111490:1;111471:7;:16;111479:7;111471:16;;;;;;;;;;;;;;;;:20;111463:71;;;;;;;;;;;;:::i;:::-;;;;;;;;;111547:21;111617:20;111631:5;111617:13;:20::i;:::-;111571:5;:15;;;111595:4;111571:30;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:66;;;;:::i;:::-;111547:90;;111648:15;111666:115;111696:7;111718:13;111746:24;111755:5;111762:7;111746:8;:24::i;:::-;111666:15;:115::i;:::-;111648:133;;111813:1;111802:7;:12;;111794:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;111909:7;111875:14;:21;111890:5;111875:21;;;;;;;;;;;;;;;:30;111897:7;111875:30;;;;;;;;;;;;;;;;:41;;;;;;;:::i;:::-;;;;;;;;111957:7;111927:19;:26;111947:5;111927:26;;;;;;;;;;;;;;;;:37;;;;;;;:::i;:::-;;;;;;;;111977:47;112000:5;112007:7;112016;111977:22;:47::i;:::-;112061:5;112040:45;;;112068:7;112077;112040:45;;;;;;;:::i;:::-;;;;;;;;111452:641;;111389:704;;:::o;116121:73::-;116158:28;116174:10;116158:7;:28::i;:::-;116121:73::o;117135:150::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;117217:6:::1;;;;;;;;;;;117216:7;117208:35;;;;;;;;;;;;:::i;:::-;;;;;;;;;117270:7;117254:13;:23;;;;;;;;;;;;:::i;:::-;;117135:150:::0;:::o;116202:820::-;116293:16;116352:18;116387:16;116397:5;116387:9;:16::i;:::-;116373:31;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;116352:52;;116419:11;116433:13;;116419:27;;116461:19;116495:25;116540:9;116535:446;116555:3;116551:1;:7;116535:446;;;116584:31;116618:11;:14;116630:1;116618:14;;;;;;;;;;;116584:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;116655:9;:16;;;116651:73;;;116696:8;;;116651:73;116772:1;116746:28;;:9;:14;;;:28;;;116742:111;;116819:9;:14;;;116799:34;;116742:111;116896:5;116875:26;;:17;:26;;;116871:95;;;116945:1;116926;116928:13;;;;;;116926:16;;;;;;;;:::i;:::-;;;;;;;:20;;;;;116871:95;116565:416;116535:446;116560:3;;;;;;;116535:446;;;;117002:1;116995:8;;;;;;116202:820;;;:::o;82962:125::-;83026:7;83053:21;83066:7;83053:12;:21::i;:::-;:26;;;83046:33;;82962:125;;;:::o;114541:418::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;114673:15:::1;;;;;;;;;;;114665:46;;;;;;;;;;;;:::i;:::-;;;;;;;;;114729:9;114724:228;114748:5;;:12;;114744:1;:16;114724:228;;;114872:9;;114858:7;;114866:1;114858:10;;;;;;;:::i;:::-;;;;;;;;114842:13;:11;:13::i;:::-;:26;;;;:::i;:::-;:39;;114834:60;;;;;;;;;;;;:::i;:::-;;;;;;;;;114909:31;114919:5;;114925:1;114919:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;114929:7;;114937:1;114929:10;;;;;;;:::i;:::-;;;;;;;;114909:9;:31::i;:::-;114762:3;;;;;:::i;:::-;;;;114724:228;;;;114541:418:::0;;;;:::o;113412:38::-;;;;:::o;80378:206::-;80442:7;80483:1;80466:19;;:5;:19;;;80462:60;;;80494:28;;;;;;;;;;;;;;80462:60;80548:12;:19;80561:5;80548:19;;;;;;;;;;;;;;;:27;;;;;;;;;;;;80540:36;;80533:43;;80378:206;;;:::o;115904:110::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;115994:12:::1;115980:11;:26;;;;115904:110:::0;:::o;69812:103::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;69877:30:::1;69904:1;69877:18;:30::i;:::-;69812:103::o:0;110205:100::-;110256:7;110283;110291:5;110283:14;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;110276:21;;110205:100;;;:::o;69161:87::-;69207:7;69234:6;;;;;;;;;;;69227:13;;69161:87;:::o;83323:104::-;83379:13;83412:7;83405:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83323:104;:::o;113457:30::-;;;;:::o;109669:109::-;109725:7;109752:9;:18;109762:7;109752:18;;;;;;;;;;;;;;;;109745:25;;109669:109;;;:::o;116022:75::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;116085:4:::1;116076:6;;:13;;;;;;;;;;;;;;;;;;116022:75::o:0;114967:512::-;74826:1;75424:7;;:19;;75416:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;74826:1;75557:7;:18;;;;115046:12:::1;;;;;;;;;;;115038:38;;;;;;;;;;;;:::i;:::-;;;;;;;;;115157:11;;115145:6;115111:19;:31;115131:10;115111:31;;;;;;;;;;;;;;;;:40;;;;:::i;:::-;115109:59;;115087:145;;;;;;;;;;;;:::i;:::-;;;;;;;;;115279:9;;115269:6;115253:13;:11;:13::i;:::-;:22;;;;:::i;:::-;:35;;115245:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;115342:9;115332:6;115320:9;;:18;;;;:::i;:::-;:31;;115312:65;;;;;;;;;;;;:::i;:::-;;;;;;;;;115390:29;115400:10;115412:6;115390:9;:29::i;:::-;115465:6;115430:19;:31;115450:10;115430:31;;;;;;;;;;;;;;;;:41;;;;;;;:::i;:::-;;;;;;;;74782:1:::0;75736:7;:22;;;;114967:512;:::o;85071:319::-;85214:12;:10;:12::i;:::-;85202:24;;:8;:24;;;85198:54;;;85235:17;;;;;;;;;;;;;;85198:54;85310:8;85265:18;:32;85284:12;:10;:12::i;:::-;85265:32;;;;;;;;;;;;;;;:42;85298:8;85265:42;;;;;;;;;;;;;;;;:53;;;;;;;;;;;;;;;;;;85363:8;85334:48;;85349:12;:10;:12::i;:::-;85334:48;;;85373:8;85334:48;;;;;;:::i;:::-;;;;;;;;85071:319;;:::o;113816:34::-;;;;;;;;;;;;;:::o;113859:54::-;;;;;;;;;;;;;;;;;:::o;86239:406::-;86406:28;86416:4;86422:2;86426:7;86406:9;:28::i;:::-;86463:15;:2;:13;;;:15::i;:::-;:89;;;;;86496:56;86527:4;86533:2;86537:7;86546:5;86496:30;:56::i;:::-;86495:57;86463:89;86445:193;;;86586:40;;;;;;;;;;;;;;86445:193;86239:406;;;;:::o;117030:97::-;117079:7;117106:13;:11;:13::i;:::-;117099:20;;117030:97;:::o;117415:205::-;117516:13;117578:23;117593:7;117578:14;:23::i;:::-;117561:50;;;;;;;;:::i;:::-;;;;;;;;;;;;;117547:65;;117415:205;;;:::o;109465:105::-;109519:7;109546;:16;109554:7;109546:16;;;;;;;;;;;;;;;;109539:23;;109465:105;;;:::o;114065:18::-;;;;;;;;;;;;;:::o;113494:31::-;;;;:::o;109255:119::-;109313:7;109340:19;:26;109360:5;109340:26;;;;;;;;;;;;;;;;109333:33;;109255:119;;;:::o;109003:95::-;109049:7;109076:14;;109069:21;;109003:95;:::o;85461:214::-;85603:4;85632:18;:25;85651:5;85632:25;;;;;;;;;;;;;;;:35;85658:8;85632:35;;;;;;;;;;;;;;;;;;;;;;;;;85625:42;;85461:214;;;;:::o;113777:32::-;;;;;;;;;;;;;:::o;115633:153::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;115713:15:::1;;;;;;;;;;;115712:16;115694:15;;:34;;;;;;;;;;;;;;;;;;115744;115762:15;;;;;;;;;;;115744:34;;;;;;:::i;:::-;;;;;;;;115633:153::o:0;70070:238::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;70193:1:::1;70173:22;;:8;:22;;;;70151:110;;;;;;;;;;;;:::i;:::-;;;;;;;;;70272:28;70291:8;70272:18;:28::i;:::-;70070:238:::0;:::o;115794:102::-;69392:12;:10;:12::i;:::-;69381:23;;:7;:5;:7::i;:::-;:23;;;69373:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;115878:10:::1;115866:9;:22;;;;115794:102:::0;:::o;38315:207::-;38445:4;38489:25;38474:40;;;:11;:40;;;;38467:47;;38315:207;;;:::o;86900:213::-;86957:4;87013:7;86994:15;:13;:15::i;:::-;:26;;:66;;;;;87047:13;;87037:7;:23;86994:66;:111;;;;;87078:11;:20;87090:7;87078:20;;;;;;;;;;;:27;;;;;;;;;;;;87077:28;86994:111;86974:131;;86900:213;;;:::o;95287:196::-;95429:2;95402:15;:24;95418:7;95402:24;;;;;;;;;;;;:29;;;;;;;;;;;;;;;;;;95467:7;95463:2;95447:28;;95456:5;95447:28;;;;;;;;;;;;95287:196;;;:::o;117628:101::-;117693:7;117720:1;117713:8;;117628:101;:::o;112271:261::-;112417:7;112509:15;112494:12;;112474:7;:16;112482:7;112474:16;;;;;;;;;;;;;;;;112458:13;:32;;;;:::i;:::-;112457:49;;;;:::i;:::-;:67;;;;:::i;:::-;112437:87;;112271:261;;;;;:::o;28289:391::-;28418:6;28393:21;:31;;28371:110;;;;;;;;;;;;:::i;:::-;;;;;;;;;28495:12;28513:9;:14;;28535:6;28513:33;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28494:52;;;28579:7;28557:115;;;;;;;;;;;;:::i;:::-;;;;;;;;;28360:320;28289:391;;:::o;90230:2130::-;90345:35;90383:21;90396:7;90383:12;:21::i;:::-;90345:59;;90443:4;90421:26;;:13;:18;;;:26;;;90417:67;;90456:28;;;;;;;;;;;;;;90417:67;90497:22;90539:4;90523:20;;:12;:10;:12::i;:::-;:20;;;:73;;;;90560:36;90577:4;90583:12;:10;:12::i;:::-;90560:16;:36::i;:::-;90523:73;:126;;;;90637:12;:10;:12::i;:::-;90613:36;;:20;90625:7;90613:11;:20::i;:::-;:36;;;90523:126;90497:153;;90668:17;90663:66;;90694:35;;;;;;;;;;;;;;90663:66;90758:1;90744:16;;:2;:16;;;90740:52;;;90769:23;;;;;;;;;;;;;;90740:52;90805:43;90827:4;90833:2;90837:7;90846:1;90805:21;:43::i;:::-;90913:35;90930:1;90934:7;90943:4;90913:8;:35::i;:::-;91274:1;91244:12;:18;91257:4;91244:18;;;;;;;;;;;;;;;:26;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91318:1;91290:12;:16;91303:2;91290:16;;;;;;;;;;;;;;;:24;;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91336:31;91370:11;:20;91382:7;91370:20;;;;;;;;;;;91336:54;;91421:2;91405:8;:13;;;:18;;;;;;;;;;;;;;;;;;91471:15;91438:8;:23;;;:49;;;;;;;;;;;;;;;;;;91739:19;91771:1;91761:7;:11;91739:33;;91787:31;91821:11;:24;91833:11;91821:24;;;;;;;;;;;91787:58;;91889:1;91864:27;;:8;:13;;;;;;;;;;;;:27;;;91860:384;;;92074:13;;92059:11;:28;92055:174;;92128:4;92112:8;:13;;;:20;;;;;;;;;;;;;;;;;;92181:13;:28;;;92155:8;:23;;;:54;;;;;;;;;;;;;;;;;;92055:174;91860:384;91219:1036;;;92291:7;92287:2;92272:27;;92281:4;92272:27;;;;;;;;;;;;92310:42;92331:4;92337:2;92341:7;92350:1;92310:20;:42::i;:::-;90334:2026;;90230:2130;;;:::o;87121:104::-;87190:27;87200:2;87204:8;87190:27;;;;;;;;;;;;:9;:27::i;:::-;87121:104;;:::o;101734:248::-;101851:123;101885:5;101928:23;;;101953:2;101957:5;101905:58;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;101851:19;:123::i;:::-;101734:248;;;:::o;81759:1141::-;81848:21;;:::i;:::-;81887:12;81902:7;81887:22;;81970:4;81951:15;:13;:15::i;:::-;:23;;:47;;;;;81985:13;;81978:4;:20;81951:47;81947:886;;;82019:31;82053:11;:17;82065:4;82053:17;;;;;;;;;;;82019:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82094:9;:16;;;82089:729;;82165:1;82139:28;;:9;:14;;;:28;;;82135:101;;82203:9;82196:16;;;;;;82135:101;82538:261;82545:4;82538:261;;;82578:6;;;;;;;;82623:11;:17;82635:4;82623:17;;;;;;;;;;;82611:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82697:1;82671:28;;:9;:14;;;:28;;;82667:109;;82739:9;82732:16;;;;;;82667:109;82538:261;;;82089:729;82000:833;81947:886;82861:31;;;;;;;;;;;;;;81759:1141;;;;:::o;70468:191::-;70542:16;70561:6;;;;;;;;;;;70542:25;;70587:8;70578:6;;:17;;;;;;;;;;;;;;;;;;70642:8;70611:40;;70632:8;70611:40;;;;;;;;;;;;70531:128;70468:191;:::o;26967:387::-;27027:4;27235:12;27302:7;27290:20;27282:28;;27345:1;27338:4;:8;27331:15;;;26967:387;;;:::o;95975:772::-;96138:4;96188:2;96172:36;;;96227:12;:10;:12::i;:::-;96258:4;96281:7;96307:5;96172:155;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;96155:585;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96515:1;96498:6;:13;:18;96494:235;;;96544:40;;;;;;;;;;;;;;96494:235;96687:6;96681:13;96672:6;96668:2;96664:15;96657:38;96155:585;96393:45;;;96383:55;;;:6;:55;;;;96376:62;;;95975:772;;;;;;:::o;83498:415::-;83616:13;83652:16;83660:7;83652;:16::i;:::-;83647:59;;83677:29;;;;;;;;;;;;;;83647:59;83719:21;83743:10;:8;:10::i;:::-;83719:34;;83809:1;83790:7;83784:21;:26;;:121;;;;;;;;;;;;;;;;;83854:7;83863:18;:7;:16;:18::i;:::-;83837:45;;;;;;;;;:::i;:::-;;;;;;;;;;;;;83784:121;83764:141;;;83498:415;;;:::o;97395:159::-;;;;;:::o;98213:158::-;;;;;:::o;87588:163::-;87711:32;87717:2;87721:8;87731:5;87738:4;87711:5;:32::i;:::-;87588:163;;;:::o;104701:802::-;105125:23;105151:106;105193:4;105151:106;;;;;;;;;;;;;;;;;105159:5;105151:27;;;;:106;;;;;:::i;:::-;105125:132;;105292:1;105272:10;:17;:21;105268:228;;;105387:10;105376:30;;;;;;;;;;;;:::i;:::-;105350:134;;;;;;;;;;;;:::i;:::-;;;;;;;;;105268:228;104771:732;104701:802;;:::o;117293:114::-;117353:13;117386;117379:20;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;117293:114;:::o;35799:723::-;35855:13;36085:1;36076:5;:10;36072:53;;;36103:10;;;;;;;;;;;;;;;;;;;;;36072:53;36135:12;36150:5;36135:20;;36166:14;36191:78;36206:1;36198:4;:9;36191:78;;36224:8;;;;;:::i;:::-;;;;36255:2;36247:10;;;;;:::i;:::-;;;36191:78;;;36279:19;36311:6;36301:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36279:39;;36329:154;36345:1;36336:5;:10;36329:154;;36373:1;36363:11;;;;;:::i;:::-;;;36440:2;36432:5;:10;;;;:::i;:::-;36419:2;:24;;;;:::i;:::-;36406:39;;36389:6;36396;36389:14;;;;;;;;:::i;:::-;;;;;:56;;;;;;;;;;;36469:2;36460:11;;;;;:::i;:::-;;;36329:154;;;36507:6;36493:21;;;;;35799:723;;;;:::o;88010:1966::-;88149:20;88172:13;;88149:36;;88214:1;88200:16;;:2;:16;;;88196:48;;;88225:19;;;;;;;;;;;;;;88196:48;88271:1;88259:8;:13;88255:44;;;88281:18;;;;;;;;;;;;;;88255:44;88312:61;88342:1;88346:2;88350:12;88364:8;88312:21;:61::i;:::-;88685:8;88650:12;:16;88663:2;88650:16;;;;;;;;;;;;;;;:24;;;:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88749:8;88709:12;:16;88722:2;88709:16;;;;;;;;;;;;;;;:29;;;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88808:2;88775:11;:25;88787:12;88775:25;;;;;;;;;;;:30;;;:35;;;;;;;;;;;;;;;;;;88875:15;88825:11;:25;88837:12;88825:25;;;;;;;;;;;:40;;;:66;;;;;;;;;;;;;;;;;;88908:20;88931:12;88908:35;;88958:11;88987:8;88972:12;:23;88958:37;;89016:4;:23;;;;;89024:15;:2;:13;;;:15::i;:::-;89016:23;89012:832;;;89060:505;89116:12;89112:2;89091:38;;89108:1;89091:38;;;;;;;;;;;;89183:212;89252:1;89285:2;89318:14;;;;;;89363:5;89183:30;:212::i;:::-;89152:365;;89453:40;;;;;;;;;;;;;;89152:365;89560:3;89544:12;:19;;89060:505;;89646:12;89629:13;;:29;89625:43;;89660:8;;;89625:43;89012:832;;;89709:120;89765:14;;;;;;89761:2;89740:40;;89757:1;89740:40;;;;;;;;;;;;89824:3;89808:12;:19;;89709:120;;89012:832;89874:12;89858:13;:28;;;;88625:1273;;89908:60;89937:1;89941:2;89945:12;89959:8;89908:20;:60::i;:::-;88138:1838;88010:1966;;;;:::o;29870:229::-;30007:12;30039:52;30061:6;30069:4;30075:1;30078:12;30039:21;:52::i;:::-;30032:59;;29870:229;;;;;:::o;31086:571::-;31256:12;31328:5;31303:21;:30;;31281:118;;;;;;;;;;;;:::i;:::-;;;;;;;;;31418:18;31429:6;31418:10;:18::i;:::-;31410:60;;;;;;;;;;;;:::i;:::-;;;;;;;;;31484:12;31498:23;31525:6;:11;;31544:5;31565:4;31525:55;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31483:97;;;;31598:51;31615:7;31624:10;31636:12;31598:16;:51::i;:::-;31591:58;;;;31086:571;;;;;;:::o;34046:712::-;34196:12;34225:7;34221:530;;;34256:10;34249:17;;;;34221:530;34390:1;34370:10;:17;:21;34366:374;;;34568:10;34562:17;34629:15;34616:10;34612:2;34608:19;34601:44;34366:374;34711:12;34704:20;;;;;;;;;;;:::i;:::-;;;;;;;;34046:712;;;;;;:::o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::o;7:126:1:-;44:7;84:42;77:5;73:54;62:65;;7:126;;;:::o;139:96::-;176:7;205:24;223:5;205:24;:::i;:::-;194:35;;139:96;;;:::o;241:118::-;328:24;346:5;328:24;:::i;:::-;323:3;316:37;241:118;;:::o;365:77::-;402:7;431:5;420:16;;365:77;;;:::o;448:118::-;535:24;553:5;535:24;:::i;:::-;530:3;523:37;448:118;;:::o;572:332::-;693:4;731:2;720:9;716:18;708:26;;744:71;812:1;801:9;797:17;788:6;744:71;:::i;:::-;825:72;893:2;882:9;878:18;869:6;825:72;:::i;:::-;572:332;;;;;:::o;910:75::-;943:6;976:2;970:9;960:19;;910:75;:::o;991:117::-;1100:1;1097;1090:12;1114:117;1223:1;1220;1213:12;1237:149;1273:7;1313:66;1306:5;1302:78;1291:89;;1237:149;;;:::o;1392:120::-;1464:23;1481:5;1464:23;:::i;:::-;1457:5;1454:34;1444:62;;1502:1;1499;1492:12;1444:62;1392:120;:::o;1518:137::-;1563:5;1601:6;1588:20;1579:29;;1617:32;1643:5;1617:32;:::i;:::-;1518:137;;;;:::o;1661:327::-;1719:6;1768:2;1756:9;1747:7;1743:23;1739:32;1736:119;;;1774:79;;:::i;:::-;1736:119;1894:1;1919:52;1963:7;1954:6;1943:9;1939:22;1919:52;:::i;:::-;1909:62;;1865:116;1661:327;;;;:::o;1994:90::-;2028:7;2071:5;2064:13;2057:21;2046:32;;1994:90;;;:::o;2090:109::-;2171:21;2186:5;2171:21;:::i;:::-;2166:3;2159:34;2090:109;;:::o;2205:210::-;2292:4;2330:2;2319:9;2315:18;2307:26;;2343:65;2405:1;2394:9;2390:17;2381:6;2343:65;:::i;:::-;2205:210;;;;:::o;2421:99::-;2473:6;2507:5;2501:12;2491:22;;2421:99;;;:::o;2526:169::-;2610:11;2644:6;2639:3;2632:19;2684:4;2679:3;2675:14;2660:29;;2526:169;;;;:::o;2701:307::-;2769:1;2779:113;2793:6;2790:1;2787:13;2779:113;;;2878:1;2873:3;2869:11;2863:18;2859:1;2854:3;2850:11;2843:39;2815:2;2812:1;2808:10;2803:15;;2779:113;;;2910:6;2907:1;2904:13;2901:101;;;2990:1;2981:6;2976:3;2972:16;2965:27;2901:101;2750:258;2701:307;;;:::o;3014:102::-;3055:6;3106:2;3102:7;3097:2;3090:5;3086:14;3082:28;3072:38;;3014:102;;;:::o;3122:364::-;3210:3;3238:39;3271:5;3238:39;:::i;:::-;3293:71;3357:6;3352:3;3293:71;:::i;:::-;3286:78;;3373:52;3418:6;3413:3;3406:4;3399:5;3395:16;3373:52;:::i;:::-;3450:29;3472:6;3450:29;:::i;:::-;3445:3;3441:39;3434:46;;3214:272;3122:364;;;;:::o;3492:313::-;3605:4;3643:2;3632:9;3628:18;3620:26;;3692:9;3686:4;3682:20;3678:1;3667:9;3663:17;3656:47;3720:78;3793:4;3784:6;3720:78;:::i;:::-;3712:86;;3492:313;;;;:::o;3811:122::-;3884:24;3902:5;3884:24;:::i;:::-;3877:5;3874:35;3864:63;;3923:1;3920;3913:12;3864:63;3811:122;:::o;3939:139::-;3985:5;4023:6;4010:20;4001:29;;4039:33;4066:5;4039:33;:::i;:::-;3939:139;;;;:::o;4084:329::-;4143:6;4192:2;4180:9;4171:7;4167:23;4163:32;4160:119;;;4198:79;;:::i;:::-;4160:119;4318:1;4343:53;4388:7;4379:6;4368:9;4364:22;4343:53;:::i;:::-;4333:63;;4289:117;4084:329;;;;:::o;4419:222::-;4512:4;4550:2;4539:9;4535:18;4527:26;;4563:71;4631:1;4620:9;4616:17;4607:6;4563:71;:::i;:::-;4419:222;;;;:::o;4647:122::-;4720:24;4738:5;4720:24;:::i;:::-;4713:5;4710:35;4700:63;;4759:1;4756;4749:12;4700:63;4647:122;:::o;4775:139::-;4821:5;4859:6;4846:20;4837:29;;4875:33;4902:5;4875:33;:::i;:::-;4775:139;;;;:::o;4920:474::-;4988:6;4996;5045:2;5033:9;5024:7;5020:23;5016:32;5013:119;;;5051:79;;:::i;:::-;5013:119;5171:1;5196:53;5241:7;5232:6;5221:9;5217:22;5196:53;:::i;:::-;5186:63;;5142:117;5298:2;5324:53;5369:7;5360:6;5349:9;5345:22;5324:53;:::i;:::-;5314:63;;5269:118;4920:474;;;;;:::o;5400:222::-;5493:4;5531:2;5520:9;5516:18;5508:26;;5544:71;5612:1;5601:9;5597:17;5588:6;5544:71;:::i;:::-;5400:222;;;;:::o;5628:104::-;5673:7;5702:24;5720:5;5702:24;:::i;:::-;5691:35;;5628:104;;;:::o;5738:138::-;5819:32;5845:5;5819:32;:::i;:::-;5812:5;5809:43;5799:71;;5866:1;5863;5856:12;5799:71;5738:138;:::o;5882:155::-;5936:5;5974:6;5961:20;5952:29;;5990:41;6025:5;5990:41;:::i;:::-;5882:155;;;;:::o;6043:345::-;6110:6;6159:2;6147:9;6138:7;6134:23;6130:32;6127:119;;;6165:79;;:::i;:::-;6127:119;6285:1;6310:61;6363:7;6354:6;6343:9;6339:22;6310:61;:::i;:::-;6300:71;;6256:125;6043:345;;;;:::o;6394:619::-;6471:6;6479;6487;6536:2;6524:9;6515:7;6511:23;6507:32;6504:119;;;6542:79;;:::i;:::-;6504:119;6662:1;6687:53;6732:7;6723:6;6712:9;6708:22;6687:53;:::i;:::-;6677:63;;6633:117;6789:2;6815:53;6860:7;6851:6;6840:9;6836:22;6815:53;:::i;:::-;6805:63;;6760:118;6917:2;6943:53;6988:7;6979:6;6968:9;6964:22;6943:53;:::i;:::-;6933:63;;6888:118;6394:619;;;;;:::o;7019:111::-;7071:7;7100:24;7118:5;7100:24;:::i;:::-;7089:35;;7019:111;;;:::o;7136:152::-;7224:39;7257:5;7224:39;:::i;:::-;7217:5;7214:50;7204:78;;7278:1;7275;7268:12;7204:78;7136:152;:::o;7294:169::-;7355:5;7393:6;7380:20;7371:29;;7409:48;7451:5;7409:48;:::i;:::-;7294:169;;;;:::o;7469:504::-;7552:6;7560;7609:2;7597:9;7588:7;7584:23;7580:32;7577:119;;;7615:79;;:::i;:::-;7577:119;7735:1;7760:68;7820:7;7811:6;7800:9;7796:22;7760:68;:::i;:::-;7750:78;;7706:132;7877:2;7903:53;7948:7;7939:6;7928:9;7924:22;7903:53;:::i;:::-;7893:63;;7848:118;7469:504;;;;;:::o;7979:117::-;8088:1;8085;8078:12;8102:117;8211:1;8208;8201:12;8225:180;8273:77;8270:1;8263:88;8370:4;8367:1;8360:15;8394:4;8391:1;8384:15;8411:281;8494:27;8516:4;8494:27;:::i;:::-;8486:6;8482:40;8624:6;8612:10;8609:22;8588:18;8576:10;8573:34;8570:62;8567:88;;;8635:18;;:::i;:::-;8567:88;8675:10;8671:2;8664:22;8454:238;8411:281;;:::o;8698:129::-;8732:6;8759:20;;:::i;:::-;8749:30;;8788:33;8816:4;8808:6;8788:33;:::i;:::-;8698:129;;;:::o;8833:308::-;8895:4;8985:18;8977:6;8974:30;8971:56;;;9007:18;;:::i;:::-;8971:56;9045:29;9067:6;9045:29;:::i;:::-;9037:37;;9129:4;9123;9119:15;9111:23;;8833:308;;;:::o;9147:154::-;9231:6;9226:3;9221;9208:30;9293:1;9284:6;9279:3;9275:16;9268:27;9147:154;;;:::o;9307:412::-;9385:5;9410:66;9426:49;9468:6;9426:49;:::i;:::-;9410:66;:::i;:::-;9401:75;;9499:6;9492:5;9485:21;9537:4;9530:5;9526:16;9575:3;9566:6;9561:3;9557:16;9554:25;9551:112;;;9582:79;;:::i;:::-;9551:112;9672:41;9706:6;9701:3;9696;9672:41;:::i;:::-;9391:328;9307:412;;;;;:::o;9739:340::-;9795:5;9844:3;9837:4;9829:6;9825:17;9821:27;9811:122;;9852:79;;:::i;:::-;9811:122;9969:6;9956:20;9994:79;10069:3;10061:6;10054:4;10046:6;10042:17;9994:79;:::i;:::-;9985:88;;9801:278;9739:340;;;;:::o;10085:509::-;10154:6;10203:2;10191:9;10182:7;10178:23;10174:32;10171:119;;;10209:79;;:::i;:::-;10171:119;10357:1;10346:9;10342:17;10329:31;10387:18;10379:6;10376:30;10373:117;;;10409:79;;:::i;:::-;10373:117;10514:63;10569:7;10560:6;10549:9;10545:22;10514:63;:::i;:::-;10504:73;;10300:287;10085:509;;;;:::o;10600:329::-;10659:6;10708:2;10696:9;10687:7;10683:23;10679:32;10676:119;;;10714:79;;:::i;:::-;10676:119;10834:1;10859:53;10904:7;10895:6;10884:9;10880:22;10859:53;:::i;:::-;10849:63;;10805:117;10600:329;;;;:::o;10935:114::-;11002:6;11036:5;11030:12;11020:22;;10935:114;;;:::o;11055:184::-;11154:11;11188:6;11183:3;11176:19;11228:4;11223:3;11219:14;11204:29;;11055:184;;;;:::o;11245:132::-;11312:4;11335:3;11327:11;;11365:4;11360:3;11356:14;11348:22;;11245:132;;;:::o;11383:108::-;11460:24;11478:5;11460:24;:::i;:::-;11455:3;11448:37;11383:108;;:::o;11497:179::-;11566:10;11587:46;11629:3;11621:6;11587:46;:::i;:::-;11665:4;11660:3;11656:14;11642:28;;11497:179;;;;:::o;11682:113::-;11752:4;11784;11779:3;11775:14;11767:22;;11682:113;;;:::o;11831:732::-;11950:3;11979:54;12027:5;11979:54;:::i;:::-;12049:86;12128:6;12123:3;12049:86;:::i;:::-;12042:93;;12159:56;12209:5;12159:56;:::i;:::-;12238:7;12269:1;12254:284;12279:6;12276:1;12273:13;12254:284;;;12355:6;12349:13;12382:63;12441:3;12426:13;12382:63;:::i;:::-;12375:70;;12468:60;12521:6;12468:60;:::i;:::-;12458:70;;12314:224;12301:1;12298;12294:9;12289:14;;12254:284;;;12258:14;12554:3;12547:10;;11955:608;;;11831:732;;;;:::o;12569:373::-;12712:4;12750:2;12739:9;12735:18;12727:26;;12799:9;12793:4;12789:20;12785:1;12774:9;12770:17;12763:47;12827:108;12930:4;12921:6;12827:108;:::i;:::-;12819:116;;12569:373;;;;:::o;12948:117::-;13057:1;13054;13047:12;13071:117;13180:1;13177;13170:12;13211:568;13284:8;13294:6;13344:3;13337:4;13329:6;13325:17;13321:27;13311:122;;13352:79;;:::i;:::-;13311:122;13465:6;13452:20;13442:30;;13495:18;13487:6;13484:30;13481:117;;;13517:79;;:::i;:::-;13481:117;13631:4;13623:6;13619:17;13607:29;;13685:3;13677:4;13669:6;13665:17;13655:8;13651:32;13648:41;13645:128;;;13692:79;;:::i;:::-;13645:128;13211:568;;;;;:::o;13802:::-;13875:8;13885:6;13935:3;13928:4;13920:6;13916:17;13912:27;13902:122;;13943:79;;:::i;:::-;13902:122;14056:6;14043:20;14033:30;;14086:18;14078:6;14075:30;14072:117;;;14108:79;;:::i;:::-;14072:117;14222:4;14214:6;14210:17;14198:29;;14276:3;14268:4;14260:6;14256:17;14246:8;14242:32;14239:41;14236:128;;;14283:79;;:::i;:::-;14236:128;13802:568;;;;;:::o;14376:934::-;14498:6;14506;14514;14522;14571:2;14559:9;14550:7;14546:23;14542:32;14539:119;;;14577:79;;:::i;:::-;14539:119;14725:1;14714:9;14710:17;14697:31;14755:18;14747:6;14744:30;14741:117;;;14777:79;;:::i;:::-;14741:117;14890:80;14962:7;14953:6;14942:9;14938:22;14890:80;:::i;:::-;14872:98;;;;14668:312;15047:2;15036:9;15032:18;15019:32;15078:18;15070:6;15067:30;15064:117;;;15100:79;;:::i;:::-;15064:117;15213:80;15285:7;15276:6;15265:9;15261:22;15213:80;:::i;:::-;15195:98;;;;14990:313;14376:934;;;;;;;:::o;15316:116::-;15386:21;15401:5;15386:21;:::i;:::-;15379:5;15376:32;15366:60;;15422:1;15419;15412:12;15366:60;15316:116;:::o;15438:133::-;15481:5;15519:6;15506:20;15497:29;;15535:30;15559:5;15535:30;:::i;:::-;15438:133;;;;:::o;15577:468::-;15642:6;15650;15699:2;15687:9;15678:7;15674:23;15670:32;15667:119;;;15705:79;;:::i;:::-;15667:119;15825:1;15850:53;15895:7;15886:6;15875:9;15871:22;15850:53;:::i;:::-;15840:63;;15796:117;15952:2;15978:50;16020:7;16011:6;16000:9;15996:22;15978:50;:::i;:::-;15968:60;;15923:115;15577:468;;;;;:::o;16051:307::-;16112:4;16202:18;16194:6;16191:30;16188:56;;;16224:18;;:::i;:::-;16188:56;16262:29;16284:6;16262:29;:::i;:::-;16254:37;;16346:4;16340;16336:15;16328:23;;16051:307;;;:::o;16364:410::-;16441:5;16466:65;16482:48;16523:6;16482:48;:::i;:::-;16466:65;:::i;:::-;16457:74;;16554:6;16547:5;16540:21;16592:4;16585:5;16581:16;16630:3;16621:6;16616:3;16612:16;16609:25;16606:112;;;16637:79;;:::i;:::-;16606:112;16727:41;16761:6;16756:3;16751;16727:41;:::i;:::-;16447:327;16364:410;;;;;:::o;16793:338::-;16848:5;16897:3;16890:4;16882:6;16878:17;16874:27;16864:122;;16905:79;;:::i;:::-;16864:122;17022:6;17009:20;17047:78;17121:3;17113:6;17106:4;17098:6;17094:17;17047:78;:::i;:::-;17038:87;;16854:277;16793:338;;;;:::o;17137:943::-;17232:6;17240;17248;17256;17305:3;17293:9;17284:7;17280:23;17276:33;17273:120;;;17312:79;;:::i;:::-;17273:120;17432:1;17457:53;17502:7;17493:6;17482:9;17478:22;17457:53;:::i;:::-;17447:63;;17403:117;17559:2;17585:53;17630:7;17621:6;17610:9;17606:22;17585:53;:::i;:::-;17575:63;;17530:118;17687:2;17713:53;17758:7;17749:6;17738:9;17734:22;17713:53;:::i;:::-;17703:63;;17658:118;17843:2;17832:9;17828:18;17815:32;17874:18;17866:6;17863:30;17860:117;;;17896:79;;:::i;:::-;17860:117;18001:62;18055:7;18046:6;18035:9;18031:22;18001:62;:::i;:::-;17991:72;;17786:287;17137:943;;;;;;;:::o;18086:359::-;18160:6;18209:2;18197:9;18188:7;18184:23;18180:32;18177:119;;;18215:79;;:::i;:::-;18177:119;18335:1;18360:68;18420:7;18411:6;18400:9;18396:22;18360:68;:::i;:::-;18350:78;;18306:132;18086:359;;;;:::o;18451:474::-;18519:6;18527;18576:2;18564:9;18555:7;18551:23;18547:32;18544:119;;;18582:79;;:::i;:::-;18544:119;18702:1;18727:53;18772:7;18763:6;18752:9;18748:22;18727:53;:::i;:::-;18717:63;;18673:117;18829:2;18855:53;18900:7;18891:6;18880:9;18876:22;18855:53;:::i;:::-;18845:63;;18800:118;18451:474;;;;;:::o;18931:182::-;19071:34;19067:1;19059:6;19055:14;19048:58;18931:182;:::o;19119:366::-;19261:3;19282:67;19346:2;19341:3;19282:67;:::i;:::-;19275:74;;19358:93;19447:3;19358:93;:::i;:::-;19476:2;19471:3;19467:12;19460:19;;19119:366;;;:::o;19491:419::-;19657:4;19695:2;19684:9;19680:18;19672:26;;19744:9;19738:4;19734:20;19730:1;19719:9;19715:17;19708:47;19772:131;19898:4;19772:131;:::i;:::-;19764:139;;19491:419;;;:::o;19916:180::-;19964:77;19961:1;19954:88;20061:4;20058:1;20051:15;20085:4;20082:1;20075:15;20102:320;20146:6;20183:1;20177:4;20173:12;20163:22;;20230:1;20224:4;20220:12;20251:18;20241:81;;20307:4;20299:6;20295:17;20285:27;;20241:81;20369:2;20361:6;20358:14;20338:18;20335:38;20332:84;;;20388:18;;:::i;:::-;20332:84;20153:269;20102:320;;;:::o;20428:225::-;20568:34;20564:1;20556:6;20552:14;20545:58;20637:8;20632:2;20624:6;20620:15;20613:33;20428:225;:::o;20659:366::-;20801:3;20822:67;20886:2;20881:3;20822:67;:::i;:::-;20815:74;;20898:93;20987:3;20898:93;:::i;:::-;21016:2;21011:3;21007:12;21000:19;;20659:366;;;:::o;21031:419::-;21197:4;21235:2;21224:9;21220:18;21212:26;;21284:9;21278:4;21274:20;21270:1;21259:9;21255:17;21248:47;21312:131;21438:4;21312:131;:::i;:::-;21304:139;;21031:419;;;:::o;21456:180::-;21504:77;21501:1;21494:88;21601:4;21598:1;21591:15;21625:4;21622:1;21615:15;21642:305;21682:3;21701:20;21719:1;21701:20;:::i;:::-;21696:25;;21735:20;21753:1;21735:20;:::i;:::-;21730:25;;21889:1;21821:66;21817:74;21814:1;21811:81;21808:107;;;21895:18;;:::i;:::-;21808:107;21939:1;21936;21932:9;21925:16;;21642:305;;;;:::o;21953:230::-;22093:34;22089:1;22081:6;22077:14;22070:58;22162:13;22157:2;22149:6;22145:15;22138:38;21953:230;:::o;22189:366::-;22331:3;22352:67;22416:2;22411:3;22352:67;:::i;:::-;22345:74;;22428:93;22517:3;22428:93;:::i;:::-;22546:2;22541:3;22537:12;22530:19;;22189:366;;;:::o;22561:419::-;22727:4;22765:2;22754:9;22750:18;22742:26;;22814:9;22808:4;22804:20;22800:1;22789:9;22785:17;22778:47;22842:131;22968:4;22842:131;:::i;:::-;22834:139;;22561:419;;;:::o;22986:60::-;23014:3;23035:5;23028:12;;22986:60;;;:::o;23052:142::-;23102:9;23135:53;23153:34;23162:24;23180:5;23162:24;:::i;:::-;23153:34;:::i;:::-;23135:53;:::i;:::-;23122:66;;23052:142;;;:::o;23200:126::-;23250:9;23283:37;23314:5;23283:37;:::i;:::-;23270:50;;23200:126;;;:::o;23332:134::-;23390:9;23423:37;23454:5;23423:37;:::i;:::-;23410:50;;23332:134;;;:::o;23472:147::-;23567:45;23606:5;23567:45;:::i;:::-;23562:3;23555:58;23472:147;;:::o;23625:348::-;23754:4;23792:2;23781:9;23777:18;23769:26;;23805:79;23881:1;23870:9;23866:17;23857:6;23805:79;:::i;:::-;23894:72;23962:2;23951:9;23947:18;23938:6;23894:72;:::i;:::-;23625:348;;;;;:::o;23979:158::-;24119:10;24115:1;24107:6;24103:14;24096:34;23979:158;:::o;24143:365::-;24285:3;24306:66;24370:1;24365:3;24306:66;:::i;:::-;24299:73;;24381:93;24470:3;24381:93;:::i;:::-;24499:2;24494:3;24490:12;24483:19;;24143:365;;;:::o;24514:419::-;24680:4;24718:2;24707:9;24703:18;24695:26;;24767:9;24761:4;24757:20;24753:1;24742:9;24738:17;24731:47;24795:131;24921:4;24795:131;:::i;:::-;24787:139;;24514:419;;;:::o;24939:143::-;24996:5;25027:6;25021:13;25012:22;;25043:33;25070:5;25043:33;:::i;:::-;24939:143;;;;:::o;25088:351::-;25158:6;25207:2;25195:9;25186:7;25182:23;25178:32;25175:119;;;25213:79;;:::i;:::-;25175:119;25333:1;25358:64;25414:7;25405:6;25394:9;25390:22;25358:64;:::i;:::-;25348:74;;25304:128;25088:351;;;;:::o;25445:165::-;25585:17;25581:1;25573:6;25569:14;25562:41;25445:165;:::o;25616:366::-;25758:3;25779:67;25843:2;25838:3;25779:67;:::i;:::-;25772:74;;25855:93;25944:3;25855:93;:::i;:::-;25973:2;25968:3;25964:12;25957:19;;25616:366;;;:::o;25988:419::-;26154:4;26192:2;26181:9;26177:18;26169:26;;26241:9;26235:4;26231:20;26227:1;26216:9;26212:17;26205:47;26269:131;26395:4;26269:131;:::i;:::-;26261:139;;25988:419;;;:::o;26413:180::-;26461:77;26458:1;26451:88;26558:4;26555:1;26548:15;26582:4;26579:1;26572:15;26599:168;26739:20;26735:1;26727:6;26723:14;26716:44;26599:168;:::o;26773:366::-;26915:3;26936:67;27000:2;26995:3;26936:67;:::i;:::-;26929:74;;27012:93;27101:3;27012:93;:::i;:::-;27130:2;27125:3;27121:12;27114:19;;26773:366;;;:::o;27145:419::-;27311:4;27349:2;27338:9;27334:18;27326:26;;27398:9;27392:4;27388:20;27384:1;27373:9;27369:17;27362:47;27426:131;27552:4;27426:131;:::i;:::-;27418:139;;27145:419;;;:::o;27570:233::-;27609:3;27632:24;27650:5;27632:24;:::i;:::-;27623:33;;27678:66;27671:5;27668:77;27665:103;;;27748:18;;:::i;:::-;27665:103;27795:1;27788:5;27784:13;27777:20;;27570:233;;;:::o;27809:181::-;27949:33;27945:1;27937:6;27933:14;27926:57;27809:181;:::o;27996:366::-;28138:3;28159:67;28223:2;28218:3;28159:67;:::i;:::-;28152:74;;28235:93;28324:3;28235:93;:::i;:::-;28353:2;28348:3;28344:12;28337:19;;27996:366;;;:::o;28368:419::-;28534:4;28572:2;28561:9;28557:18;28549:26;;28621:9;28615:4;28611:20;28607:1;28596:9;28592:17;28585:47;28649:131;28775:4;28649:131;:::i;:::-;28641:139;;28368:419;;;:::o;28793:163::-;28933:15;28929:1;28921:6;28917:14;28910:39;28793:163;:::o;28962:366::-;29104:3;29125:67;29189:2;29184:3;29125:67;:::i;:::-;29118:74;;29201:93;29290:3;29201:93;:::i;:::-;29319:2;29314:3;29310:12;29303:19;;28962:366;;;:::o;29334:419::-;29500:4;29538:2;29527:9;29523:18;29515:26;;29587:9;29581:4;29577:20;29573:1;29562:9;29558:17;29551:47;29615:131;29741:4;29615:131;:::i;:::-;29607:139;;29334:419;;;:::o;29759:223::-;29899:34;29895:1;29887:6;29883:14;29876:58;29968:6;29963:2;29955:6;29951:15;29944:31;29759:223;:::o;29988:366::-;30130:3;30151:67;30215:2;30210:3;30151:67;:::i;:::-;30144:74;;30227:93;30316:3;30227:93;:::i;:::-;30345:2;30340:3;30336:12;30329:19;;29988:366;;;:::o;30360:419::-;30526:4;30564:2;30553:9;30549:18;30541:26;;30613:9;30607:4;30603:20;30599:1;30588:9;30584:17;30577:47;30641:131;30767:4;30641:131;:::i;:::-;30633:139;;30360:419;;;:::o;30785:348::-;30825:7;30848:20;30866:1;30848:20;:::i;:::-;30843:25;;30882:20;30900:1;30882:20;:::i;:::-;30877:25;;31070:1;31002:66;30998:74;30995:1;30992:81;30987:1;30980:9;30973:17;30969:105;30966:131;;;31077:18;;:::i;:::-;30966:131;31125:1;31122;31118:9;31107:20;;30785:348;;;;:::o;31139:171::-;31279:23;31275:1;31267:6;31263:14;31256:47;31139:171;:::o;31316:366::-;31458:3;31479:67;31543:2;31538:3;31479:67;:::i;:::-;31472:74;;31555:93;31644:3;31555:93;:::i;:::-;31673:2;31668:3;31664:12;31657:19;;31316:366;;;:::o;31688:419::-;31854:4;31892:2;31881:9;31877:18;31869:26;;31941:9;31935:4;31931:20;31927:1;31916:9;31912:17;31905:47;31969:131;32095:4;31969:131;:::i;:::-;31961:139;;31688:419;;;:::o;32113:148::-;32215:11;32252:3;32237:18;;32113:148;;;;:::o;32267:377::-;32373:3;32401:39;32434:5;32401:39;:::i;:::-;32456:89;32538:6;32533:3;32456:89;:::i;:::-;32449:96;;32554:52;32599:6;32594:3;32587:4;32580:5;32576:16;32554:52;:::i;:::-;32631:6;32626:3;32622:16;32615:23;;32377:267;32267:377;;;;:::o;32650:155::-;32790:7;32786:1;32778:6;32774:14;32767:31;32650:155;:::o;32811:400::-;32971:3;32992:84;33074:1;33069:3;32992:84;:::i;:::-;32985:91;;33085:93;33174:3;33085:93;:::i;:::-;33203:1;33198:3;33194:11;33187:18;;32811:400;;;:::o;33217:541::-;33450:3;33472:95;33563:3;33554:6;33472:95;:::i;:::-;33465:102;;33584:148;33728:3;33584:148;:::i;:::-;33577:155;;33749:3;33742:10;;33217:541;;;;:::o;33764:225::-;33904:34;33900:1;33892:6;33888:14;33881:58;33973:8;33968:2;33960:6;33956:15;33949:33;33764:225;:::o;33995:366::-;34137:3;34158:67;34222:2;34217:3;34158:67;:::i;:::-;34151:74;;34234:93;34323:3;34234:93;:::i;:::-;34352:2;34347:3;34343:12;34336:19;;33995:366;;;:::o;34367:419::-;34533:4;34571:2;34560:9;34556:18;34548:26;;34620:9;34614:4;34610:20;34606:1;34595:9;34591:17;34584:47;34648:131;34774:4;34648:131;:::i;:::-;34640:139;;34367:419;;;:::o;34792:180::-;34840:77;34837:1;34830:88;34937:4;34934:1;34927:15;34961:4;34958:1;34951:15;34978:185;35018:1;35035:20;35053:1;35035:20;:::i;:::-;35030:25;;35069:20;35087:1;35069:20;:::i;:::-;35064:25;;35108:1;35098:35;;35113:18;;:::i;:::-;35098:35;35155:1;35152;35148:9;35143:14;;34978:185;;;;:::o;35169:191::-;35209:4;35229:20;35247:1;35229:20;:::i;:::-;35224:25;;35263:20;35281:1;35263:20;:::i;:::-;35258:25;;35302:1;35299;35296:8;35293:34;;;35307:18;;:::i;:::-;35293:34;35352:1;35349;35345:9;35337:17;;35169:191;;;;:::o;35366:179::-;35506:31;35502:1;35494:6;35490:14;35483:55;35366:179;:::o;35551:366::-;35693:3;35714:67;35778:2;35773:3;35714:67;:::i;:::-;35707:74;;35790:93;35879:3;35790:93;:::i;:::-;35908:2;35903:3;35899:12;35892:19;;35551:366;;;:::o;35923:419::-;36089:4;36127:2;36116:9;36112:18;36104:26;;36176:9;36170:4;36166:20;36162:1;36151:9;36147:17;36140:47;36204:131;36330:4;36204:131;:::i;:::-;36196:139;;35923:419;;;:::o;36348:147::-;36449:11;36486:3;36471:18;;36348:147;;;;:::o;36501:114::-;;:::o;36621:398::-;36780:3;36801:83;36882:1;36877:3;36801:83;:::i;:::-;36794:90;;36893:93;36982:3;36893:93;:::i;:::-;37011:1;37006:3;37002:11;36995:18;;36621:398;;;:::o;37025:379::-;37209:3;37231:147;37374:3;37231:147;:::i;:::-;37224:154;;37395:3;37388:10;;37025:379;;;:::o;37410:245::-;37550:34;37546:1;37538:6;37534:14;37527:58;37619:28;37614:2;37606:6;37602:15;37595:53;37410:245;:::o;37661:366::-;37803:3;37824:67;37888:2;37883:3;37824:67;:::i;:::-;37817:74;;37900:93;37989:3;37900:93;:::i;:::-;38018:2;38013:3;38009:12;38002:19;;37661:366;;;:::o;38033:419::-;38199:4;38237:2;38226:9;38222:18;38214:26;;38286:9;38280:4;38276:20;38272:1;38261:9;38257:17;38250:47;38314:131;38440:4;38314:131;:::i;:::-;38306:139;;38033:419;;;:::o;38458:98::-;38509:6;38543:5;38537:12;38527:22;;38458:98;;;:::o;38562:168::-;38645:11;38679:6;38674:3;38667:19;38719:4;38714:3;38710:14;38695:29;;38562:168;;;;:::o;38736:360::-;38822:3;38850:38;38882:5;38850:38;:::i;:::-;38904:70;38967:6;38962:3;38904:70;:::i;:::-;38897:77;;38983:52;39028:6;39023:3;39016:4;39009:5;39005:16;38983:52;:::i;:::-;39060:29;39082:6;39060:29;:::i;:::-;39055:3;39051:39;39044:46;;38826:270;38736:360;;;;:::o;39102:640::-;39297:4;39335:3;39324:9;39320:19;39312:27;;39349:71;39417:1;39406:9;39402:17;39393:6;39349:71;:::i;:::-;39430:72;39498:2;39487:9;39483:18;39474:6;39430:72;:::i;:::-;39512;39580:2;39569:9;39565:18;39556:6;39512:72;:::i;:::-;39631:9;39625:4;39621:20;39616:2;39605:9;39601:18;39594:48;39659:76;39730:4;39721:6;39659:76;:::i;:::-;39651:84;;39102:640;;;;;;;:::o;39748:141::-;39804:5;39835:6;39829:13;39820:22;;39851:32;39877:5;39851:32;:::i;:::-;39748:141;;;;:::o;39895:349::-;39964:6;40013:2;40001:9;39992:7;39988:23;39984:32;39981:119;;;40019:79;;:::i;:::-;39981:119;40139:1;40164:63;40219:7;40210:6;40199:9;40195:22;40164:63;:::i;:::-;40154:73;;40110:127;39895:349;;;;:::o;40250:435::-;40430:3;40452:95;40543:3;40534:6;40452:95;:::i;:::-;40445:102;;40564:95;40655:3;40646:6;40564:95;:::i;:::-;40557:102;;40676:3;40669:10;;40250:435;;;;;:::o;40691:137::-;40745:5;40776:6;40770:13;40761:22;;40792:30;40816:5;40792:30;:::i;:::-;40691:137;;;;:::o;40834:345::-;40901:6;40950:2;40938:9;40929:7;40925:23;40921:32;40918:119;;;40956:79;;:::i;:::-;40918:119;41076:1;41101:61;41154:7;41145:6;41134:9;41130:22;41101:61;:::i;:::-;41091:71;;41047:125;40834:345;;;;:::o;41185:229::-;41325:34;41321:1;41313:6;41309:14;41302:58;41394:12;41389:2;41381:6;41377:15;41370:37;41185:229;:::o;41420:366::-;41562:3;41583:67;41647:2;41642:3;41583:67;:::i;:::-;41576:74;;41659:93;41748:3;41659:93;:::i;:::-;41777:2;41772:3;41768:12;41761:19;;41420:366;;;:::o;41792:419::-;41958:4;41996:2;41985:9;41981:18;41973:26;;42045:9;42039:4;42035:20;42031:1;42020:9;42016:17;42009:47;42073:131;42199:4;42073:131;:::i;:::-;42065:139;;41792:419;;;:::o;42217:176::-;42249:1;42266:20;42284:1;42266:20;:::i;:::-;42261:25;;42300:20;42318:1;42300:20;:::i;:::-;42295:25;;42339:1;42329:35;;42344:18;;:::i;:::-;42329:35;42385:1;42382;42378:9;42373:14;;42217:176;;;;:::o;42399:225::-;42539:34;42535:1;42527:6;42523:14;42516:58;42608:8;42603:2;42595:6;42591:15;42584:33;42399:225;:::o;42630:366::-;42772:3;42793:67;42857:2;42852:3;42793:67;:::i;:::-;42786:74;;42869:93;42958:3;42869:93;:::i;:::-;42987:2;42982:3;42978:12;42971:19;;42630:366;;;:::o;43002:419::-;43168:4;43206:2;43195:9;43191:18;43183:26;;43255:9;43249:4;43245:20;43241:1;43230:9;43226:17;43219:47;43283:131;43409:4;43283:131;:::i;:::-;43275:139;;43002:419;;;:::o;43427:179::-;43567:31;43563:1;43555:6;43551:14;43544:55;43427:179;:::o;43612:366::-;43754:3;43775:67;43839:2;43834:3;43775:67;:::i;:::-;43768:74;;43851:93;43940:3;43851:93;:::i;:::-;43969:2;43964:3;43960:12;43953:19;;43612:366;;;:::o;43984:419::-;44150:4;44188:2;44177:9;44173:18;44165:26;;44237:9;44231:4;44227:20;44223:1;44212:9;44208:17;44201:47;44265:131;44391:4;44265:131;:::i;:::-;44257:139;;43984:419;;;:::o;44409:373::-;44513:3;44541:38;44573:5;44541:38;:::i;:::-;44595:88;44676:6;44671:3;44595:88;:::i;:::-;44588:95;;44692:52;44737:6;44732:3;44725:4;44718:5;44714:16;44692:52;:::i;:::-;44769:6;44764:3;44760:16;44753:23;;44517:265;44409:373;;;;:::o;44788:271::-;44918:3;44940:93;45029:3;45020:6;44940:93;:::i;:::-;44933:100;;45050:3;45043:10;;44788:271;;;;:::o

Swarm Source

ipfs://0a61d2076ec37ff00cda8bb3d448ff38bdc17c1ab6dde57df6e6acaf9e8a7be8

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

Liquid Keys from [ApeLiquid.io](https://ApeLiquid.io) unlock the Liquid Forge and the Evolution Chamber, which allows the holder to evolve a Mythic Creature by sacrificing a Liquid Legend, Liquid Invader, or Azuki Ape Social Club and by burning a Liquid Artifact to activate the Evolution Chamber.

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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