ETH Price: $3,391.89 (+1.71%)

Token

Particlon (PART)
 

Overview

Max Total Supply

1,356 PART

Holders

369

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

Balance
2 PART
0x28DBB1A5d6C69fCA7F507FCF555D1189519b50e7
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Particlon is ushering in the next generation of NFTs by pushing the boundaries of utility & possibilities with the Charged Particles Protocol, an NFT Protocol from early 2020 allowing you to nest additional assets - fungible or non-fungi...

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Particlon

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

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

// SPDX-License-Identifier: MIT
// If you think you may have found a vulnerability
// File: @opengsn/contracts/src/interfaces/IRelayRecipient.sol


pragma solidity >=0.6.0;

/**
 * a contract must implement this interface in order to support relayed transaction.
 * It is better to inherit the BaseRelayRecipient as its implementation.
 */
abstract contract IRelayRecipient {

    /**
     * return if the forwarder is trusted to forward relayed transactions to us.
     * the forwarder is required to verify the sender's signature, and verify
     * the call is not a replay.
     */
    function isTrustedForwarder(address forwarder) public virtual view returns(bool);

    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, then the real sender is appended as the last 20 bytes
     * of the msg.data.
     * otherwise, return `msg.sender`
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender() internal virtual view returns (address);

    /**
     * return the msg.data of this call.
     * if the call came through our trusted forwarder, then the real sender was appended as the last 20 bytes
     * of the msg.data - so this method will strip those 20 bytes off.
     * otherwise (if the call was made directly and not through the forwarder), return `msg.data`
     * should be used in the contract instead of msg.data, where this difference matters.
     */
    function _msgData() internal virtual view returns (bytes calldata);

    function versionRecipient() external virtual view returns (string memory);
}

// File: @opengsn/contracts/src/BaseRelayRecipient.sol


// solhint-disable no-inline-assembly
pragma solidity >=0.6.9;


/**
 * A base contract to be inherited by any contract that want to receive relayed transactions
 * A subclass must use "_msgSender()" instead of "msg.sender"
 */
abstract contract BaseRelayRecipient is IRelayRecipient {

    /*
     * Forwarder singleton we accept calls from
     */
    address private _trustedForwarder;

    function trustedForwarder() public virtual view returns (address){
        return _trustedForwarder;
    }

    function _setTrustedForwarder(address _forwarder) internal {
        _trustedForwarder = _forwarder;
    }

    function isTrustedForwarder(address forwarder) public virtual override view returns(bool) {
        return forwarder == _trustedForwarder;
    }

    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, return the original sender.
     * otherwise, return `msg.sender`.
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender() internal override virtual view returns (address ret) {
        if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // so we trust that the last bytes of msg.data are the verified sender address.
            // extract sender address from the end of msg.data
            assembly {
                ret := shr(96,calldataload(sub(calldatasize(),20)))
            }
        } else {
            ret = msg.sender;
        }
    }

    /**
     * return the msg.data of this call.
     * if the call came through our trusted forwarder, then the real sender was appended as the last 20 bytes
     * of the msg.data - so this method will strip those 20 bytes off.
     * otherwise (if the call was made directly and not through the forwarder), return `msg.data`
     * should be used in the contract instead of msg.data, where this difference matters.
     */
    function _msgData() internal override virtual view returns (bytes calldata ret) {
        if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
            return msg.data[0:msg.data.length-20];
        } else {
            return msg.data;
        }
    }
}

// File: contracts/lib/RelayRecipient.sol



pragma solidity ^0.8.0;

// import "@opengsn/gsn/contracts/BaseRelayRecipient.sol";


contract RelayRecipient is BaseRelayRecipient {
    function versionRecipient() external pure override returns (string memory) {
        return "1.0.0-beta.1/charged-particles.relay.recipient";
    }
}

// File: contracts/lib/TokenInfo.sol



// TokenInfo.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity ^0.8.0;

library TokenInfo {
    /**
     * @dev Returns true if `account` is a contract.
     * @dev Taken from OpenZeppelin library
     *
     * [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) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            codehash := extcodehash(account)
        }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     * @dev Taken from OpenZeppelin library
     *
     * 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,
        uint256 gasLimit
    ) internal {
        require(
            address(this).balance >= amount,
            "TokenInfo: insufficient balance"
        );

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = (gasLimit > 0)
            ? recipient.call{value: amount, gas: gasLimit}("")
            : recipient.call{value: amount}("");
        require(
            success,
            "TokenInfo: unable to send value, recipient may have reverted"
        );
    }
}

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


// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

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

// File: contracts/interfaces/ISignatureVerifier.sol


pragma solidity ^0.8.0;

interface ISignatureVerifier {
    function verify(
        address _signer,
        address _to,
        uint256 _amount,
        uint256 _nonce,
        bytes memory signature
    ) external pure returns (bool);
}

// File: contracts/interfaces/IChargedParticles.sol



// IChargedParticles.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity ^0.8.0;

/**
 * @notice Interface for Charged Particles
 */
interface IChargedParticles {
    /***********************************|
    |             Public API            |
    |__________________________________*/

    function getStateAddress() external view returns (address stateAddress);

    function getSettingsAddress()
        external
        view
        returns (address settingsAddress);

    function getManagersAddress()
        external
        view
        returns (address managersAddress);

    function getFeesForDeposit(uint256 assetAmount)
        external
        view
        returns (uint256 protocolFee);

    function baseParticleMass(
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken
    ) external returns (uint256);

    function currentParticleCharge(
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken
    ) external returns (uint256);

    function currentParticleKinetics(
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken
    ) external returns (uint256);

    function currentParticleCovalentBonds(
        address contractAddress,
        uint256 tokenId,
        string calldata basketManagerId
    ) external view returns (uint256);

    /***********************************|
    |        Particle Mechanics         |
    |__________________________________*/

    function energizeParticle(
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken,
        uint256 assetAmount,
        address referrer
    ) external returns (uint256 yieldTokensAmount);

    function dischargeParticle(
        address receiver,
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken
    ) external returns (uint256 creatorAmount, uint256 receiverAmount);

    function dischargeParticleAmount(
        address receiver,
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken,
        uint256 assetAmount
    ) external returns (uint256 creatorAmount, uint256 receiverAmount);

    function dischargeParticleForCreator(
        address receiver,
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken,
        uint256 assetAmount
    ) external returns (uint256 receiverAmount);

    function releaseParticle(
        address receiver,
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken
    ) external returns (uint256 creatorAmount, uint256 receiverAmount);

    function releaseParticleAmount(
        address receiver,
        address contractAddress,
        uint256 tokenId,
        string calldata walletManagerId,
        address assetToken,
        uint256 assetAmount
    ) external returns (uint256 creatorAmount, uint256 receiverAmount);

    function covalentBond(
        address contractAddress,
        uint256 tokenId,
        string calldata basketManagerId,
        address nftTokenAddress,
        uint256 nftTokenId
    ) external returns (bool success);

    function breakCovalentBond(
        address receiver,
        address contractAddress,
        uint256 tokenId,
        string calldata basketManagerId,
        address nftTokenAddress,
        uint256 nftTokenId
    ) external returns (bool success);

    /***********************************|
    |          Particle Events          |
    |__________________________________*/

    event Initialized(address indexed initiator);
    event ControllerSet(address indexed controllerAddress, string controllerId);
    event DepositFeeSet(uint256 depositFee);
    event ProtocolFeesCollected(
        address indexed assetToken,
        uint256 depositAmount,
        uint256 feesCollected
    );
}

// File: contracts/interfaces/IChargedState.sol



// IChargedSettings.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity ^0.8.0;

/**
 * @notice Interface for Charged State
 */
interface IChargedState {
    /***********************************|
    |      Only NFT Owner/Operator      |
    |__________________________________*/

    function setDischargeApproval(
        address contractAddress,
        uint256 tokenId,
        address operator
    ) external;

    function setReleaseApproval(
        address contractAddress,
        uint256 tokenId,
        address operator
    ) external;

    function setBreakBondApproval(
        address contractAddress,
        uint256 tokenId,
        address operator
    ) external;

    function setTimelockApproval(
        address contractAddress,
        uint256 tokenId,
        address operator
    ) external;

    function setApprovalForAll(
        address contractAddress,
        uint256 tokenId,
        address operator
    ) external;

    function setPermsForRestrictCharge(
        address contractAddress,
        uint256 tokenId,
        bool state
    ) external;

    function setPermsForAllowDischarge(
        address contractAddress,
        uint256 tokenId,
        bool state
    ) external;

    function setPermsForAllowRelease(
        address contractAddress,
        uint256 tokenId,
        bool state
    ) external;

    function setPermsForRestrictBond(
        address contractAddress,
        uint256 tokenId,
        bool state
    ) external;

    function setPermsForAllowBreakBond(
        address contractAddress,
        uint256 tokenId,
        bool state
    ) external;

    function setDischargeTimelock(
        address contractAddress,
        uint256 tokenId,
        uint256 unlockBlock
    ) external;

    function setReleaseTimelock(
        address contractAddress,
        uint256 tokenId,
        uint256 unlockBlock
    ) external;

    function setBreakBondTimelock(
        address contractAddress,
        uint256 tokenId,
        uint256 unlockBlock
    ) external;

    /***********************************|
    |         Only NFT Contract         |
    |__________________________________*/

    function setTemporaryLock(
        address contractAddress,
        uint256 tokenId,
        bool isLocked
    ) external;
}

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


// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/token/ERC1155/IERC1155.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;


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

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

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

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

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

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

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

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

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

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


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

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

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


// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

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

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


// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

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

// File: contracts/interfaces/IERC721Consumable.sol


pragma solidity ^0.8.0;


/// @title ERC-721 Consumer Role extension
///  Note: the ERC-165 identifier for this interface is 0x953c8dfa
interface IERC721Consumable is IERC721 {
    /// @notice Emitted when `owner` changes the `consumer` of an NFT
    /// The zero address for consumer indicates that there is no consumer address
    /// When a Transfer event emits, this also indicates that the consumer address
    /// for that NFT (if any) is set to none
    event ConsumerChanged(
        address indexed owner,
        address indexed consumer,
        uint256 indexed tokenId
    );

    /// @notice Get the consumer address of an NFT
    /// @dev The zero address indicates that there is no consumer
    /// Throws if `_tokenId` is not a valid NFT
    /// @param _tokenId The NFT to get the consumer address for
    /// @return The consumer address for this NFT, or the zero address if there is none
    function consumerOf(uint256 _tokenId) external view returns (address);

    /// @notice Change or reaffirm the consumer address for an NFT
    /// @dev The zero address indicates there is no consumer address
    /// Throws unless `msg.sender` is the current NFT owner, an authorised
    /// operator of the current owner or approved address
    /// Throws if `_tokenId` is not valid NFT
    /// @param _consumer The new consumer of the NFT
    function changeConsumer(address _consumer, uint256 _tokenId) external;
}

// File: contracts/interfaces/IParticlon.sol



// Particlon.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity ^0.8.0;

// pragma experimental ABIEncoderV2;

// import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// import "@openzeppelin/contracts/utils/math/SafeMath.sol";
// import "@openzeppelin/contracts/access/Ownable.sol";
// import "@openzeppelin/contracts/utils/Counters.sol";
// import "@openzeppelin/contracts/utils/Address.sol";
// import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

// import "./BlackholePrevention.sol";
// import "./RelayRecipient.sol";


interface IParticlon is IERC721 {
    enum EMintPhase {
        CLOSED,
        CLAIM,
        WHITELIST,
        PUBLIC
    }
    /// @notice Andy was here
    event NewBaseURI(string indexed _uri);
    event NewSignerAddress(address indexed signer);
    event NewMintPhase(EMintPhase indexed mintPhase);
    event NewMintPrice(uint256 price);

    event AssetTokenSet(address indexed assetToken);
    event ChargedStateSet(address indexed chargedState);
    event ChargedSettingsSet(address indexed chargedSettings);
    event ChargedParticlesSet(address indexed chargedParticles);

    event SalePriceSet(uint256 indexed tokenId, uint256 salePrice);
    event CreatorRoyaltiesSet(uint256 indexed tokenId, uint256 royaltiesPct);
    event ParticlonSold(
        uint256 indexed tokenId,
        address indexed oldOwner,
        address indexed newOwner,
        uint256 salePrice,
        address creator,
        uint256 creatorRoyalties
    );
    event RoyaltiesClaimed(address indexed receiver, uint256 amountClaimed);

    /***********************************|
    |              Public               |
    |__________________________________*/

    function creatorOf(uint256 tokenId) external view returns (address);

    function getSalePrice(uint256 tokenId) external view returns (uint256);

    function getLastSellPrice(uint256 tokenId) external view returns (uint256);

    function getCreatorRoyalties(address account)
        external
        view
        returns (uint256);

    function getCreatorRoyaltiesPct(uint256 tokenId)
        external
        view
        returns (uint256);

    function getCreatorRoyaltiesReceiver(uint256 tokenId)
        external
        view
        returns (address);

    function buyParticlon(uint256 tokenId, uint256 gasLimit)
        external
        payable
        returns (bool);

    function claimCreatorRoyalties() external returns (uint256);

    // function createParticlonForSale(
    //     address creator,
    //     address receiver,
    //     // string memory tokenMetaUri,
    //     uint256 royaltiesPercent,
    //     uint256 salePrice
    // ) external returns (uint256 newTokenId);

    function mint(uint256 amount) external payable returns (bool);

    function mintWhitelist(
        uint256 amountMint,
        uint256 amountAllowed,
        uint256 nonce,
        bytes calldata signature
    ) external payable returns (bool);

    function mintFree(
        uint256 amountMint,
        uint256 amountAllowed,
        uint256 nonce,
        bytes calldata signature
    ) external returns (bool);

    // function batchParticlonsForSale(
    //     address creator,
    //     uint256 annuityPercent,
    //     uint256 royaltiesPercent,
    //     uint256[] calldata salePrices
    // ) external;

    // function createParticlonsForSale(
    //     address creator,
    //     address receiver,
    //     uint256 royaltiesPercent,
    //     // string[] calldata tokenMetaUris,
    //     uint256[] calldata salePrices
    // ) external returns (bool);

    // Andy was here

    /***********************************|
    |     Only Token Creator/Owner      |
    |__________________________________*/

    function setSalePrice(uint256 tokenId, uint256 salePrice) external;

    function setRoyaltiesPct(uint256 tokenId, uint256 royaltiesPct) external;

    function setCreatorRoyaltiesReceiver(uint256 tokenId, address receiver)
        external;
}

// File: @openzeppelin/contracts/security/ReentrancyGuard.sol


// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

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

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


// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

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

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


// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

// File: contracts/lib/ERC721A.sol


// Creator: Chiru Labs

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 1;
    }

    /**
     * @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
    ) internal virtual {
        /// @dev Andy was here, made it internal virtual to work with Charged Particles
        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 {}
}

// File: @openzeppelin/contracts/security/Pausable.sol


// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)

pragma solidity ^0.8.0;


/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

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


// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

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

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


// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

    /**
     * @dev Moves `amount` tokens from the caller's account to `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);

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

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

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


// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

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

// File: contracts/lib/BlackholePrevention.sol



// BlackholePrevention.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity ^0.8.0;






/**
 * @notice Prevents ETH or Tokens from getting stuck in a contract by allowing
 *  the Owner/DAO to pull them out on behalf of a user
 * This is only meant to contracts that are not expected to hold tokens, but do handle transferring them.
 */
contract BlackholePrevention {
    using Address for address payable;
    using SafeERC20 for IERC20;

    event WithdrawStuckEther(address indexed receiver, uint256 amount);
    event WithdrawStuckERC20(
        address indexed receiver,
        address indexed tokenAddress,
        uint256 amount
    );
    event WithdrawStuckERC721(
        address indexed receiver,
        address indexed tokenAddress,
        uint256 indexed tokenId
    );
    event WithdrawStuckERC1155(
        address indexed receiver,
        address indexed tokenAddress,
        uint256 indexed tokenId,
        uint256 amount
    );

    function _withdrawEther(address payable receiver, uint256 amount)
        internal
        virtual
    {
        require(receiver != address(0x0), "BHP:E-403");
        if (address(this).balance >= amount) {
            receiver.sendValue(amount);
            emit WithdrawStuckEther(receiver, amount);
        }
    }

    function _withdrawERC20(
        address payable receiver,
        address tokenAddress,
        uint256 amount
    ) internal virtual {
        require(receiver != address(0x0), "BHP:E-403");
        if (IERC20(tokenAddress).balanceOf(address(this)) >= amount) {
            IERC20(tokenAddress).safeTransfer(receiver, amount);
            emit WithdrawStuckERC20(receiver, tokenAddress, amount);
        }
    }

    function _withdrawERC721(
        address payable receiver,
        address tokenAddress,
        uint256 tokenId
    ) internal virtual {
        require(receiver != address(0x0), "BHP:E-403");
        if (IERC721(tokenAddress).ownerOf(tokenId) == address(this)) {
            IERC721(tokenAddress).transferFrom(
                address(this),
                receiver,
                tokenId
            );
            emit WithdrawStuckERC721(receiver, tokenAddress, tokenId);
        }
    }

    function _withdrawERC1155(
        address payable receiver,
        address tokenAddress,
        uint256 tokenId,
        uint256 amount
    ) internal virtual {
        require(receiver != address(0x0), "BHP:E-403");
        if (
            IERC1155(tokenAddress).balanceOf(address(this), tokenId) >= amount
        ) {
            IERC1155(tokenAddress).safeTransferFrom(
                address(this),
                receiver,
                tokenId,
                amount,
                ""
            );
            emit WithdrawStuckERC1155(receiver, tokenAddress, tokenId, amount);
        }
    }
}

// File: contracts/Particlon.sol



// ParticlonB.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity ^0.8.0;
















contract Particlon is
    IParticlon,
    ERC721A,
    IERC721Consumable,
    Ownable,
    Pausable,
    RelayRecipient,
    ReentrancyGuard,
    BlackholePrevention
{
    // using SafeMath for uint256; // not needed since solidity 0.8
    using TokenInfo for address payable;
    using Strings for uint256;

    /// @dev In case we want to revoke the consumer part
    bool internal _revokeConsumerOnTransfer;

    /// @notice Address used to generate cryptographic signatures for whitelisted addresses
    address internal _signer = 0xE8cF9826C7702411bb916c447D759E0E631d2e68;

    uint256 internal _nonceClaim = 69;
    uint256 internal _nonceWL = 420;

    uint256 public constant MAX_SUPPLY = 10069;
    uint256 public constant INITIAL_PRICE = 0.15 ether;

    uint256 internal constant PERCENTAGE_SCALE = 1e4; // 10000  (100%)
    uint256 internal constant MAX_ROYALTIES = 8e3; // 8000   (80%)

    // Charged Particles V1 mainnet

    IChargedState internal _chargedState =
        IChargedState(0xB29256073C63960daAa398f1227D0adBC574341C);
    // IChargedSettings internal _chargedSettings;
    IChargedParticles internal _chargedParticles =
        IChargedParticles(0xaB1a1410EA40930755C1330Cc0fB3367897C8c41);

    /// @notice This needs to be set using the setAssetToken in order to get approved
    address internal _assetToken;

    // This right here drops the size so it doesn't break the limitation
    // Enable optimization also has to be tured on!
    ISignatureVerifier internal constant _signatureVerifier =
        ISignatureVerifier(0x47a0915747565E8264296457b894068fe5CA9186);

    uint256 internal _mintPrice;

    string internal _baseUri =
        "ipfs://QmQrdG1cESrBenNUaTmxckFm4gJwgLdkqTGxNLuh4t5vo8/";

    // Mapping from token ID to consumer address
    mapping(uint256 => address) _tokenConsumers;

    mapping(uint256 => address) internal _tokenCreator;
    mapping(uint256 => uint256) internal _tokenCreatorRoyaltiesPct;
    mapping(uint256 => address) internal _tokenCreatorRoyaltiesRedirect;
    mapping(address => uint256) internal _tokenCreatorClaimableRoyalties;

    mapping(uint256 => uint256) internal _tokenSalePrice;
    mapping(uint256 => uint256) internal _tokenLastSellPrice;

    /// @notice Adhere to limits per whitelisted wallet for claim mint phase
    mapping(address => uint256) internal _mintPassMinted;

    /// @notice Adhere to limits per whitelisted wallet for whitelist mint phase
    mapping(address => uint256) internal _whitelistedAddressMinted;

    /// @notice set to CLOSED by default
    EMintPhase public mintPhase;

    /***********************************|
    |          Initialization           |
    |__________________________________*/

    constructor() ERC721A("Particlon", "PART") {
        _mintPrice = INITIAL_PRICE;
    }

    /***********************************|
    |              Public               |
    |__________________________________*/

    // Define an "onlyOwner" switch
    function setRevokeConsumerOnTransfer(bool state) external onlyOwner {
        _revokeConsumerOnTransfer = state;
    }

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

    /**
     * @dev See {IERC721Consumable-consumerOf}
     */
    function consumerOf(uint256 _tokenId) external view returns (address) {
        require(
            _exists(_tokenId),
            "ERC721Consumable: consumer query for nonexistent token"
        );
        return _tokenConsumers[_tokenId];
    }

    function creatorOf(uint256 tokenId)
        external
        view
        override
        returns (address)
    {
        return _tokenCreator[tokenId];
    }

    function getSalePrice(uint256 tokenId)
        external
        view
        override
        returns (uint256)
    {
        return _tokenSalePrice[tokenId];
    }

    function getLastSellPrice(uint256 tokenId)
        external
        view
        override
        returns (uint256)
    {
        return _tokenLastSellPrice[tokenId];
    }

    function getCreatorRoyalties(address account)
        external
        view
        override
        returns (uint256)
    {
        return _tokenCreatorClaimableRoyalties[account];
    }

    function getCreatorRoyaltiesPct(uint256 tokenId)
        external
        view
        override
        returns (uint256)
    {
        return _tokenCreatorRoyaltiesPct[tokenId];
    }

    function getCreatorRoyaltiesReceiver(uint256 tokenId)
        external
        view
        override
        returns (address)
    {
        return _creatorRoyaltiesReceiver(tokenId);
    }

    function claimCreatorRoyalties()
        external
        override
        nonReentrant
        whenNotPaused
        returns (uint256)
    {
        return _claimCreatorRoyalties(_msgSender());
    }

    /***********************************|
    |      Create Multiple Particlons   |
    |__________________________________*/

    /// @notice Andy was here
    function mint(uint256 amount)
        external
        payable
        override
        nonReentrant
        whenNotPaused
        notBeforePhase(EMintPhase.PUBLIC)
        whenRemainingSupply
        requirePayment(amount)
        returns (bool)
    {
        // They may have minted 10, but if only 2 remain in supply, then they will only get 2, so only pay for 2
        uint256 actualPrice = _mintAmount(amount, _msgSender());
        _refundOverpayment(actualPrice, 0); // dont worry about gasLimit here as the "minter" could only hook themselves
        return true;
    }

    /// @notice Andy was here
    function mintWhitelist(
        uint256 amountMint,
        uint256 amountAllowed,
        uint256 nonce,
        bytes calldata signature
    )
        external
        payable
        override
        nonReentrant
        whenNotPaused
        notBeforePhase(EMintPhase.WHITELIST)
        whenRemainingSupply
        requirePayment(amountMint)
        requireWhitelist(amountMint, amountAllowed, nonce, signature)
        returns (bool)
    {
        // They may have been whitelisted to mint 10, but if only 2 remain in supply, then they will only get 2, so only pay for 2
        uint256 actualPrice = _mintAmount(amountMint, _msgSender());
        _refundOverpayment(actualPrice, 0);
        return true;
    }

    function mintFree(
        uint256 amountMint,
        uint256 amountAllowed,
        uint256 nonce,
        bytes calldata signature
    )
        external
        override
        whenNotPaused
        notBeforePhase(EMintPhase.CLAIM)
        whenRemainingSupply
        requirePass(amountMint, amountAllowed, nonce, signature)
        returns (bool)
    {
        // They may have been whitelisted to mint 10, but if only 2 remain in supply, then they will only get 2
        _mintAmount(amountMint, _msgSender());
        return true;
    }

    /***********************************|
    |           Buy Particlons          |
    |__________________________________*/

    function buyParticlon(uint256 tokenId, uint256 gasLimit)
        external
        payable
        override
        nonReentrant
        whenNotPaused
        returns (bool)
    {
        _buyParticlon(tokenId, gasLimit);
        return true;
    }

    /***********************************|
    |     Only Token Creator/Owner      |
    |__________________________________*/

    function setSalePrice(uint256 tokenId, uint256 salePrice)
        external
        override
        whenNotPaused
        onlyTokenOwnerOrApproved(tokenId)
    {
        _setSalePrice(tokenId, salePrice);
    }

    function setRoyaltiesPct(uint256 tokenId, uint256 royaltiesPct)
        external
        override
        whenNotPaused
        onlyTokenCreator(tokenId)
        onlyTokenOwnerOrApproved(tokenId)
    {
        _setRoyaltiesPct(tokenId, royaltiesPct);
    }

    function setCreatorRoyaltiesReceiver(uint256 tokenId, address receiver)
        external
        override
        whenNotPaused
        onlyTokenCreator(tokenId)
    {
        _tokenCreatorRoyaltiesRedirect[tokenId] = receiver;
    }

    /**
     * @dev See {IERC721Consumable-changeConsumer}
     */
    function changeConsumer(address _consumer, uint256 _tokenId) external {
        address owner = this.ownerOf(_tokenId);
        require(
            _msgSender() == owner ||
                _msgSender() == getApproved(_tokenId) ||
                isApprovedForAll(owner, _msgSender()),
            "ERC721Consumable: changeConsumer caller is not owner nor approved"
        );
        _changeConsumer(owner, _consumer, _tokenId);
    }

    /***********************************|
    |          Only Admin/DAO           |
    |__________________________________*/

    // Andy was here (Andy is everywhere)

    function setSignerAddress(address signer) external onlyOwner {
        _signer = signer;
        emit NewSignerAddress(signer);
    }

    // In case we need to "undo" a signature/prevent it from being used,
    // This is easier than changing the signer
    // we would also need to remake all unused signatures
    function setNonces(uint256 nonceClaim, uint256 nonceWL) external onlyOwner {
        _nonceClaim = nonceClaim;
        _nonceWL = nonceWL;
    }

    function setAssetToken(address assetToken) external onlyOwner {
        _assetToken = assetToken;
        // Need to Approve Charged Particles to transfer Assets from Particlon
        IERC20(assetToken).approve(
            address(_chargedParticles),
            type(uint256).max
        );
        emit AssetTokenSet(assetToken);
    }

    function setMintPrice(uint256 price) external onlyOwner {
        _mintPrice = price;
        emit NewMintPrice(price);
    }

    /// @notice This is needed for the reveal
    function setURI(string memory uri) external onlyOwner {
        _baseUri = uri;
        emit NewBaseURI(uri);
    }

    function setMintPhase(EMintPhase _mintPhase) external onlyOwner {
        mintPhase = _mintPhase;
        emit NewMintPhase(_mintPhase);
    }

    function setPausedState(bool state) external onlyOwner {
        state ? _pause() : _unpause(); // these emit events
    }

    /**
     * @dev Setup the ChargedParticles Interface
     */
    function setChargedParticles(address chargedParticles) external onlyOwner {
        _chargedParticles = IChargedParticles(chargedParticles);
        emit ChargedParticlesSet(chargedParticles);
    }

    /// @dev Setup the Charged-State Controller
    function setChargedState(address stateController) external onlyOwner {
        _chargedState = IChargedState(stateController);
        emit ChargedStateSet(stateController);
    }

    /// @dev Setup the Charged-Settings Controller
    // function setChargedSettings(address settings) external onlyOwner {
    //     _chargedSettings = IChargedSettings(settings);
    //     emit ChargedSettingsSet(settings);
    // }

    function setTrustedForwarder(address _trustedForwarder) external onlyOwner {
        _setTrustedForwarder(_trustedForwarder); // Andy was here, trustedForwarder is already defined in opengsn/contracts/src/BaseRelayRecipient.sol
    }

    /***********************************|
    |          Only Admin/DAO           |
    |      (blackhole prevention)       |
    |__________________________________*/

    function withdrawEther(address payable receiver, uint256 amount)
        external
        onlyOwner
    {
        _withdrawEther(receiver, amount);
    }

    function withdrawERC20(
        address payable receiver,
        address tokenAddress,
        uint256 amount
    ) external onlyOwner {
        _withdrawERC20(receiver, tokenAddress, amount);
    }

    function withdrawERC721(
        address payable receiver,
        address tokenAddress,
        uint256 tokenId
    ) external onlyOwner {
        _withdrawERC721(receiver, tokenAddress, tokenId);
    }

    /***********************************|
    |         Private Functions         |
    |__________________________________*/

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

    function _mintAmount(uint256 amount, address creator)
        internal
        returns (uint256 actualPrice)
    {
        uint256 newTokenId = totalSupply();
        // newTokenId is equal to the supply at this stage
        if (newTokenId + amount > MAX_SUPPLY) {
            amount = MAX_SUPPLY - newTokenId;
        }
        // totalSupply += amount;

        // _safeMint's second argument now takes in a quantity, not a tokenId.
        _safeMint(creator, amount);
        actualPrice = amount * _mintPrice; // Charge people for the ACTUAL amount minted;

        uint256 assetAmount;
        newTokenId++;
        for (uint256 i; i < amount; i++) {
            // Set the first minters as the creators
            _tokenCreator[newTokenId + i] = creator;
            assetAmount += _getAssetAmount(newTokenId + i);
            // _chargeParticlon(newTokenId, "generic", assetAmount);
        }
        // Put all ERC20 tokens into the first Particlon to save a lot of gas
        _chargeParticlon(newTokenId, "generic", assetAmount);
    }

    /**
     * @dev Changes the consumer
     * Requirement: `tokenId` must exist
     */
    function _changeConsumer(
        address _owner,
        address _consumer,
        uint256 _tokenId
    ) internal {
        _tokenConsumers[_tokenId] = _consumer;
        emit ConsumerChanged(_owner, _consumer, _tokenId);
    }

    function _beforeTokenTransfers(
        address _from,
        address _to,
        uint256 _startTokenId,
        uint256 _quantity
    ) internal virtual override(ERC721A) {
        if (_from == address(0)) {
            return;
        }
        super._beforeTokenTransfers(_from, _to, _startTokenId, _quantity);

        require(!paused(), "ERC721Pausable: token transfer while paused");

        if (_revokeConsumerOnTransfer) {
            /// @notice quantity is always one in this case
            _changeConsumer(_from, address(0), _startTokenId);
        }
    }

    function _setSalePrice(uint256 tokenId, uint256 salePrice) internal {
        _tokenSalePrice[tokenId] = salePrice;

        // Temp-Lock/Unlock NFT
        //  prevents front-running the sale and draining the value of the NFT just before sale
        _chargedState.setTemporaryLock(address(this), tokenId, (salePrice > 0));

        emit SalePriceSet(tokenId, salePrice);
    }

    function _setRoyaltiesPct(uint256 tokenId, uint256 royaltiesPct) internal {
        require(royaltiesPct <= MAX_ROYALTIES, "PRT:E-421"); // Andy was here
        _tokenCreatorRoyaltiesPct[tokenId] = royaltiesPct;
        emit CreatorRoyaltiesSet(tokenId, royaltiesPct);
    }

    function _creatorRoyaltiesReceiver(uint256 tokenId)
        internal
        view
        returns (address)
    {
        address receiver = _tokenCreatorRoyaltiesRedirect[tokenId];
        if (receiver == address(0x0)) {
            receiver = _tokenCreator[tokenId];
        }
        return receiver;
    }

    /// @notice The tokens from a batch are being nested into the first NFT minted in that batch
    function _getAssetAmount(uint256 tokenId) internal pure returns (uint256) {
        if (tokenId == MAX_SUPPLY) {
            return 1596 * 10**18;
        } else if (tokenId > 9000) {
            return 1403 * 10**18;
        } else if (tokenId > 6000) {
            return 1000 * 10**18;
        } else if (tokenId > 3000) {
            return 1500 * 10**18;
        } else if (tokenId > 1000) {
            return 1750 * 10**18;
        }
        return 2500 * 10**18;
    }

    function _chargeParticlon(
        uint256 tokenId,
        string memory walletManagerId,
        uint256 assetAmount
    ) internal {
        address _self = address(this);
        _chargedParticles.energizeParticle(
            _self,
            tokenId,
            walletManagerId,
            _assetToken,
            assetAmount,
            _self
        );
    }

    function _buyParticlon(uint256 _tokenId, uint256 _gasLimit)
        internal
        returns (
            address contractAddress,
            uint256 tokenId,
            address oldOwner,
            address newOwner,
            uint256 salePrice,
            address royaltiesReceiver,
            uint256 creatorAmount
        )
    {
        contractAddress = address(this);
        tokenId = _tokenId;
        salePrice = _tokenSalePrice[_tokenId];
        require(salePrice > 0, "PRT:E-416");
        require(msg.value >= salePrice, "PRT:E-414");

        uint256 ownerAmount = salePrice;
        // creatorAmount;
        oldOwner = ownerOf(_tokenId);
        newOwner = _msgSender();

        // Creator Royalties
        royaltiesReceiver = _creatorRoyaltiesReceiver(_tokenId);
        uint256 royaltiesPct = _tokenCreatorRoyaltiesPct[_tokenId];
        uint256 lastSellPrice = _tokenLastSellPrice[_tokenId];
        if (
            royaltiesPct > 0 && lastSellPrice > 0 && salePrice > lastSellPrice
        ) {
            creatorAmount =
                ((salePrice - lastSellPrice) * royaltiesPct) /
                PERCENTAGE_SCALE;
            ownerAmount -= creatorAmount;
        }
        _tokenLastSellPrice[_tokenId] = salePrice;

        // Reserve Royalties for Creator
        if (creatorAmount > 0) {
            _tokenCreatorClaimableRoyalties[royaltiesReceiver] += creatorAmount;
        }

        // Transfer Token
        _transfer(oldOwner, newOwner, _tokenId);

        emit ParticlonSold(
            _tokenId,
            oldOwner,
            newOwner,
            salePrice,
            royaltiesReceiver,
            creatorAmount
        );

        // Transfer Payment
        if (ownerAmount > 0) {
            payable(oldOwner).sendValue(ownerAmount, _gasLimit);
        }
        _refundOverpayment(salePrice, _gasLimit);
    }

    /**
     * @dev Pays out the Creator Royalties of the calling account
     * @param receiver  The receiver of the claimable royalties
     * @return          The amount of Creator Royalties claimed
     */
    function _claimCreatorRoyalties(address receiver)
        internal
        returns (uint256)
    {
        uint256 claimableAmount = _tokenCreatorClaimableRoyalties[receiver];
        require(claimableAmount > 0, "PRT:E-411");

        delete _tokenCreatorClaimableRoyalties[receiver];
        payable(receiver).sendValue(claimableAmount, 0);

        emit RoyaltiesClaimed(receiver, claimableAmount);

        // Andy was here
        return claimableAmount;
    }

    function _refundOverpayment(uint256 threshold, uint256 gasLimit) internal {
        // Andy was here, removed SafeMath
        uint256 overage = msg.value - threshold;
        if (overage > 0) {
            payable(_msgSender()).sendValue(overage, gasLimit);
        }
    }

    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal override {
        // Unlock NFT
        _tokenSalePrice[tokenId] = 0; // Andy was here
        _chargedState.setTemporaryLock(address(this), tokenId, false);

        super._transfer(from, to, tokenId);
    }

    /***********************************|
    |          GSN/MetaTx Relay         |
    |__________________________________*/

    /// @dev See {BaseRelayRecipient-_msgSender}.
    /// Andy: removed payable
    function _msgSender()
        internal
        view
        override(BaseRelayRecipient, Context)
        returns (address)
    {
        return BaseRelayRecipient._msgSender();
    }

    /// @dev See {BaseRelayRecipient-_msgData}.
    function _msgData()
        internal
        view
        override(BaseRelayRecipient, Context)
        returns (bytes memory)
    {
        return BaseRelayRecipient._msgData();
    }

    /// @dev This is missing from ERC721A for some reason.
    function _isApprovedOrOwner(address spender, uint256 tokenId)
        internal
        view
        virtual
        returns (bool)
    {
        require(
            _exists(tokenId),
            "ERC721: operator query for nonexistent token"
        );
        address owner = ownerOf(tokenId);
        return (spender == owner ||
            isApprovedForAll(owner, spender) ||
            getApproved(tokenId) == spender);
    }

    /***********************************|
    |             Modifiers             |
    |__________________________________*/

    // Andy was here
    modifier notBeforePhase(EMintPhase _mintPhase) {
        require(mintPhase >= _mintPhase, "MINT PHASE ERR");
        _;
    }

    modifier whenRemainingSupply() {
        require(totalSupply() <= MAX_SUPPLY, "SUPPLY LIMIT");
        _;
    }

    modifier requirePayment(uint256 amount) {
        uint256 fullPrice = amount * _mintPrice;
        require(msg.value >= fullPrice, "LOW ETH");
        _;
    }

    modifier requireWhitelist(
        uint256 amountMint,
        uint256 amountAllowed,
        uint256 nonce,
        bytes calldata signature
    ) {
        require(amountMint <= amountAllowed, "AMOUNT ERR");
        require(nonce == _nonceWL, "NONCE ERR");
        require(
            _signatureVerifier.verify(
                _signer,
                _msgSender(),
                amountAllowed,
                nonce, // prevent WL signatures being used for claiming
                signature
            ),
            "SIGNATURE ERR"
        );
        require(
            _whitelistedAddressMinted[_msgSender()] + amountMint <=
                amountAllowed,
            "CLAIM ERR"
        );
        _whitelistedAddressMinted[_msgSender()] += amountMint;
        _;
    }

    /// @notice A snapshot is taken before the mint (mint pass NFT count is taken into consideration)
    modifier requirePass(
        uint256 amountMint,
        uint256 amountAllowed,
        uint256 nonce,
        bytes calldata signature
    ) {
        require(amountMint <= amountAllowed, "AMOUNT ERR");
        require(nonce == _nonceClaim, "NONCE ERR");
        require(
            _signatureVerifier.verify(
                _signer,
                _msgSender(),
                amountAllowed,
                nonce,
                signature
            ),
            "SIGNATURE ERR"
        );
        require(
            _mintPassMinted[_msgSender()] + amountMint <= amountAllowed,
            "CLAIM ERR"
        );
        _mintPassMinted[_msgSender()] += amountMint;
        _;
    }

    modifier onlyTokenOwnerOrApproved(uint256 tokenId) {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "PRT:E-105");
        _;
    }

    modifier onlyTokenCreator(uint256 tokenId) {
        require(_tokenCreator[tokenId] == _msgSender(), "PRT:E-104");
        _;
    }
}

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":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"assetToken","type":"address"}],"name":"AssetTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chargedParticles","type":"address"}],"name":"ChargedParticlesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chargedSettings","type":"address"}],"name":"ChargedSettingsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chargedState","type":"address"}],"name":"ChargedStateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"consumer","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ConsumerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"royaltiesPct","type":"uint256"}],"name":"CreatorRoyaltiesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"_uri","type":"string"}],"name":"NewBaseURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum IParticlon.EMintPhase","name":"mintPhase","type":"uint8"}],"name":"NewMintPhase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"NewMintPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"NewSignerAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"salePrice","type":"uint256"},{"indexed":false,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"uint256","name":"creatorRoyalties","type":"uint256"}],"name":"ParticlonSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountClaimed","type":"uint256"}],"name":"RoyaltiesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"SalePriceSet","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawStuckERC1155","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawStuckERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"WithdrawStuckERC721","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawStuckEther","type":"event"},{"inputs":[],"name":"INITIAL_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"buyParticlon","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_consumer","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"changeConsumer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimCreatorRoyalties","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"consumerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"creatorOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getCreatorRoyalties","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCreatorRoyaltiesPct","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCreatorRoyaltiesReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getLastSellPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getSalePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMint","type":"uint256"},{"internalType":"uint256","name":"amountAllowed","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"mintFree","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintPhase","outputs":[{"internalType":"enum IParticlon.EMintPhase","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMint","type":"uint256"},{"internalType":"uint256","name":"amountAllowed","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"mintWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetToken","type":"address"}],"name":"setAssetToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"chargedParticles","type":"address"}],"name":"setChargedParticles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stateController","type":"address"}],"name":"setChargedState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"setCreatorRoyaltiesReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IParticlon.EMintPhase","name":"_mintPhase","type":"uint8"}],"name":"setMintPhase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"setMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonceClaim","type":"uint256"},{"internalType":"uint256","name":"nonceWL","type":"uint256"}],"name":"setNonces","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setPausedState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setRevokeConsumerOnTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"royaltiesPct","type":"uint256"}],"name":"setRoyaltiesPct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"setSalePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"setSignerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_trustedForwarder","type":"address"}],"name":"setTrustedForwarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"name":"setURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"versionRecipient","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"withdrawERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"}]

600b805474e8cf9826c7702411bb916c447d759e0e631d2e6800610100600160a81b03199091161790556045600c556101a4600d55600e80546001600160a01b031990811673b29256073c63960daaa398f1227d0adbc574341c17909155600f805490911673ab1a1410ea40930755c1330cc0fb3367897c8c4117905560e06040526036608081815290620048bd60a0398051620000a691601291602090910190620001fc565b50348015620000b457600080fd5b5060408051808201825260098152682830b93a34b1b637b760b91b6020808301918252835180850190945260048452631410549560e21b9084015281519192916200010291600291620001fc565b50805162000118906003906020840190620001fc565b5050600160005550620001346200012e62000158565b62000174565b6008805460ff60a01b191690556001600a55670214e8348c4f0000601155620002de565b60006200016f620001c660201b620022841760201c565b905090565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060143610801590620001e457506009546001600160a01b031633145b15620001f7575060131936013560601c90565b503390565b8280546200020a90620002a2565b90600052602060002090601f0160209004810192826200022e576000855562000279565b82601f106200024957805160ff191683800117855562000279565b8280016001018555821562000279579182015b82811115620002795782518255916020019190600101906200025c565b50620002879291506200028b565b5090565b5b808211156200028757600081556001016200028c565b600181811c90821680620002b757607f821691505b602082108103620002d857634e487b7160e01b600052602260045260246000fd5b50919050565b6145cf80620002ee6000396000f3fe6080604052600436106103355760003560e01c80636e5559fd116101ab578063a0712d68116100f7578063da74222811610095578063e985e9c51161006f578063e985e9c5146109a4578063f2fde38b146109ed578063f4a0a52814610a0d578063f8eb5fc514610a2d57600080fd5b8063da74222814610944578063db9f60ff14610964578063e58923311461098457600080fd5b8063b7683e93116100d1578063b7683e93146108c4578063b88d4fde146108e4578063c87b56dd14610904578063c8c680d51461092457600080fd5b8063a0712d6814610864578063a22cb46514610877578063ad82c42c1461089757600080fd5b80637987df1711610164578063846ec08c1161013e578063846ec08c146107e85780638da5cb5b1461081e57806395d89b411461083c57806397b36dc51461085157600080fd5b80637987df171461078e5780637c5e2795146107ae5780637da0a877146107ca57600080fd5b80636e5559fd146106e657806370a082311461070657806370b5aecb14610726578063715018a61461074657806371e715f41461075b57806371ecfcb31461077b57600080fd5b80632fc7779711610285578063486ff0cd11610223578063589a1743116101fd578063589a17431461065c5780635c975abb146106925780636348af34146106b15780636352211e146106c657600080fd5b8063486ff0cd146105f8578063522f68151461060d578063572b6c051461062d57600080fd5b80634025feb21161025f5780634025feb21461057857806342842e0e1461059857806344004cc1146105b857806346aa05b0146105d857600080fd5b80632fc777971461052257806331c07bbf1461054257806332cb6b0c1461056257600080fd5b8063095ea7b3116102f257806323b872dd116102cc57806323b872dd14610495578063250b2c80146104b557806326bde5aa146104e25780632d1465dd1461050257600080fd5b8063095ea7b31461042b57806317881cbf1461044b57806318160ddd1461047257600080fd5b806301ffc9a71461033a57806302fe53051461036f578063046dc16614610391578063053992c5146103b157806306fdde03146103d1578063081812fc146103f3575b600080fd5b34801561034657600080fd5b5061035a610355366004613d63565b610a5a565b60405190151581526020015b60405180910390f35b34801561037b57600080fd5b5061038f61038a366004613e0c565b610a85565b005b34801561039d57600080fd5b5061038f6103ac366004613e6a565b610b2c565b3480156103bd57600080fd5b5061038f6103cc366004613e87565b610bc7565b3480156103dd57600080fd5b506103e6610c4a565b6040516103669190613f01565b3480156103ff57600080fd5b5061041361040e366004613f14565b610cdc565b6040516001600160a01b039091168152602001610366565b34801561043757600080fd5b5061038f610446366004613f2d565b610d20565b34801561045757600080fd5b50601c546104659060ff1681565b6040516103669190613f6f565b34801561047e57600080fd5b50610487610dba565b604051908152602001610366565b3480156104a157600080fd5b5061038f6104b0366004613f97565b610dc8565b3480156104c157600080fd5b506104876104d0366004613f14565b60009081526019602052604090205490565b3480156104ee57600080fd5b5061038f6104fd366004613e6a565b610dd3565b34801561050e57600080fd5b5061035a61051d366004613fd8565b610edf565b34801561052e57600080fd5b5061038f61053d366004614065565b61119c565b34801561054e57600080fd5b5061038f61055d366004614095565b611253565b34801561056e57600080fd5b5061048761275581565b34801561058457600080fd5b5061038f610593366004613f97565b6112fe565b3480156105a457600080fd5b5061038f6105b3366004613f97565b611352565b3480156105c457600080fd5b5061038f6105d3366004613f97565b61136d565b3480156105e457600080fd5b5061038f6105f33660046140c4565b6113c1565b34801561060457600080fd5b506103e661141d565b34801561061957600080fd5b5061038f610628366004613f2d565b61143d565b34801561063957600080fd5b5061035a610648366004613e6a565b6009546001600160a01b0391821691161490565b34801561066857600080fd5b50610413610677366004613f14565b6000908152601460205260409020546001600160a01b031690565b34801561069e57600080fd5b50600854600160a01b900460ff1661035a565b3480156106bd57600080fd5b50610487611494565b3480156106d257600080fd5b506104136106e1366004613f14565b611501565b3480156106f257600080fd5b5061038f610701366004613e6a565b611513565b34801561071257600080fd5b50610487610721366004613e6a565b6115a6565b34801561073257600080fd5b5061038f610741366004613f2d565b6115f5565b34801561075257600080fd5b5061038f61173a565b34801561076757600080fd5b50610413610776366004613f14565b61178f565b61035a610789366004613e87565b61179a565b34801561079a57600080fd5b5061038f6107a9366004613e87565b61180d565b3480156107ba57600080fd5b50610487670214e8348c4f000081565b3480156107d657600080fd5b506009546001600160a01b0316610413565b3480156107f457600080fd5b50610487610803366004613e6a565b6001600160a01b031660009081526017602052604090205490565b34801561082a57600080fd5b506008546001600160a01b0316610413565b34801561084857600080fd5b506103e6611861565b61035a61085f366004613fd8565b611870565b61035a610872366004613f14565b611bb1565b34801561088357600080fd5b5061038f6108923660046140e1565b611cdf565b3480156108a357600080fd5b506104876108b2366004613f14565b60009081526015602052604090205490565b3480156108d057600080fd5b5061038f6108df366004613e6a565b611db1565b3480156108f057600080fd5b5061038f6108ff36600461410f565b611e44565b34801561091057600080fd5b506103e661091f366004613f14565b611e95565b34801561093057600080fd5b5061038f61093f366004613e87565b611f19565b34801561095057600080fd5b5061038f61095f366004613e6a565b611fef565b34801561097057600080fd5b5061038f61097f3660046140c4565b612059565b34801561099057600080fd5b5061041361099f366004613f14565b6120b7565b3480156109b057600080fd5b5061035a6109bf36600461418f565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b3480156109f957600080fd5b5061038f610a08366004613e6a565b612149565b348015610a1957600080fd5b5061038f610a28366004613f14565b612200565b348015610a3957600080fd5b50610487610a48366004613f14565b60009081526018602052604090205490565b60006001600160e01b03198216634a9e46fd60e11b1480610a7f5750610a7f826122b8565b92915050565b610a8d612308565b6001600160a01b0316610aa86008546001600160a01b031690565b6001600160a01b031614610ad75760405162461bcd60e51b8152600401610ace906141bd565b60405180910390fd5b8051610aea906012906020840190613cb4565b5080604051610af991906141f2565b604051908190038120907f325d37e8fb549c86966f09bc3e6f62eb3afa93b255d6e3234338001f3d80bd8690600090a250565b610b34612308565b6001600160a01b0316610b4f6008546001600160a01b031690565b6001600160a01b031614610b755760405162461bcd60e51b8152600401610ace906141bd565b600b8054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517fee8162dfe409d975b252297226f4d86a293dbeecb9e3c5e64b837dd2758509e290600090a250565b600854600160a01b900460ff1615610bf15760405162461bcd60e51b8152600401610ace9061420e565b81610c03610bfd612308565b82612317565b610c3b5760405162461bcd60e51b81526020600482015260096024820152685052543a452d31303560b81b6044820152606401610ace565b610c458383612401565b505050565b606060028054610c5990614238565b80601f0160208091040260200160405190810160405280929190818152602001828054610c8590614238565b8015610cd25780601f10610ca757610100808354040283529160200191610cd2565b820191906000526020600020905b815481529060010190602001808311610cb557829003601f168201915b5050505050905090565b6000610ce7826124bd565b610d04576040516333d1c03960e21b815260040160405180910390fd5b506000908152600660205260409020546001600160a01b031690565b6000610d2b82611501565b9050806001600160a01b0316836001600160a01b031603610d5f5760405163250fdee360e21b815260040160405180910390fd5b806001600160a01b0316610d71612308565b6001600160a01b031614158015610d915750610d8f816109bf612308565b155b15610daf576040516367d9dca160e11b815260040160405180910390fd5b610c458383836124f6565b600154600054036000190190565b610c45838383612552565b610ddb612308565b6001600160a01b0316610df66008546001600160a01b031690565b6001600160a01b031614610e1c5760405162461bcd60e51b8152600401610ace906141bd565b601080546001600160a01b0319166001600160a01b03838116918217909255600f5460405163095ea7b360e01b81529216600483015260001960248301529063095ea7b3906044016020604051808303816000875af1158015610e83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea79190614272565b506040516001600160a01b038216907fbdaa8f7ade01473981aef419539e6c190d409f50b144a7a796efd2777607920c90600090a250565b600854600090600160a01b900460ff1615610f0c5760405162461bcd60e51b8152600401610ace9061420e565b600180601c5460ff166003811115610f2657610f26613f59565b1015610f445760405162461bcd60e51b8152600401610ace9061428f565b612755610f4f610dba565b1115610f6d5760405162461bcd60e51b8152600401610ace906142b7565b868686868683851115610faf5760405162461bcd60e51b815260206004820152600a60248201526920a6a7aaa72a1022a92960b11b6044820152606401610ace565b600c548314610fec5760405162461bcd60e51b81526020600482015260096024820152682727a721a29022a92960b91b6044820152606401610ace565b600b547347a0915747565e8264296457b894068fe5ca91869063cffc18eb9061010090046001600160a01b0316611021612308565b878787876040518763ffffffff1660e01b8152600401611046969594939291906142dd565b602060405180830381865afa158015611063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110879190614272565b6110c35760405162461bcd60e51b815260206004820152600d60248201526c29a4a3a720aa2aa9229022a92960991b6044820152606401610ace565b8385601a60006110d1612308565b6001600160a01b03166001600160a01b03168152602001908152602001600020546110fc919061434f565b11156111365760405162461bcd60e51b815260206004820152600960248201526821a620a4a69022a92960b91b6044820152606401610ace565b84601a6000611143612308565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611172919061434f565b9091555061118990508c611184612308565b6125d8565b5060019c9b505050505050505050505050565b600854600160a01b900460ff16156111c65760405162461bcd60e51b8152600401610ace9061420e565b816111cf612308565b6000828152601460205260409020546001600160a01b039081169116146112245760405162461bcd60e51b81526020600482015260096024820152681414950e914b4c4c0d60ba1b6044820152606401610ace565b5060009182526016602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b61125b612308565b6001600160a01b03166112766008546001600160a01b031690565b6001600160a01b03161461129c5760405162461bcd60e51b8152600401610ace906141bd565b601c805482919060ff191660018360038111156112bb576112bb613f59565b02179055508060038111156112d2576112d2613f59565b6040517fcae7e973d86fb577229be71728483bccd6ca3b5c5bf6ad354c31e6482455c4f090600090a250565b611306612308565b6001600160a01b03166113216008546001600160a01b031690565b6001600160a01b0316146113475760405162461bcd60e51b8152600401610ace906141bd565b610c458383836126da565b610c4583838360405180602001604052806000815250611e44565b611375612308565b6001600160a01b03166113906008546001600160a01b031690565b6001600160a01b0316146113b65760405162461bcd60e51b8152600401610ace906141bd565b610c45838383612827565b6113c9612308565b6001600160a01b03166113e46008546001600160a01b031690565b6001600160a01b03161461140a5760405162461bcd60e51b8152600401610ace906141bd565b600b805460ff1916911515919091179055565b60606040518060600160405280602e815260200161456c602e9139905090565b611445612308565b6001600160a01b03166114606008546001600160a01b031690565b6001600160a01b0316146114865760405162461bcd60e51b8152600401610ace906141bd565b6114908282612922565b5050565b60006002600a54036114b85760405162461bcd60e51b8152600401610ace90614367565b6002600a55600854600160a01b900460ff16156114e75760405162461bcd60e51b8152600401610ace9061420e565b6114f76114f2612308565b61299c565b90506001600a5590565b600061150c82612a5e565b5192915050565b61151b612308565b6001600160a01b03166115366008546001600160a01b031690565b6001600160a01b03161461155c5760405162461bcd60e51b8152600401610ace906141bd565b600f80546001600160a01b0319166001600160a01b0383169081179091556040517f5ce0e6b7fd36339ee97339831b6c72694ecee88c62aab49919d9cabe0a732e4190600090a250565b60006001600160a01b0382166115cf576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526005602052604090205467ffffffffffffffff1690565b6040516331a9108f60e11b8152600481018290526000903090636352211e90602401602060405180830381865afa158015611634573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611658919061439e565b9050806001600160a01b031661166c612308565b6001600160a01b031614806116a1575061168582610cdc565b6001600160a01b0316611696612308565b6001600160a01b0316145b806116b357506116b3816109bf612308565b61172f5760405162461bcd60e51b815260206004820152604160248201527f455243373231436f6e73756d61626c653a206368616e6765436f6e73756d657260448201527f2063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656064820152601960fa1b608482015260a401610ace565b610c45818484612b87565b611742612308565b6001600160a01b031661175d6008546001600160a01b031690565b6001600160a01b0316146117835760405162461bcd60e51b8152600401610ace906141bd565b61178d6000612be3565b565b6000610a7f82612c35565b60006002600a54036117be5760405162461bcd60e51b8152600401610ace90614367565b6002600a55600854600160a01b900460ff16156117ed5760405162461bcd60e51b8152600401610ace9061420e565b6117f78383612c6f565b50505050505050600190506001600a5592915050565b611815612308565b6001600160a01b03166118306008546001600160a01b031690565b6001600160a01b0316146118565760405162461bcd60e51b8152600401610ace906141bd565b600c91909155600d55565b606060038054610c5990614238565b60006002600a54036118945760405162461bcd60e51b8152600401610ace90614367565b6002600a55600854600160a01b900460ff16156118c35760405162461bcd60e51b8152600401610ace9061420e565b600280601c5460ff1660038111156118dd576118dd613f59565b10156118fb5760405162461bcd60e51b8152600401610ace9061428f565b612755611906610dba565b11156119245760405162461bcd60e51b8152600401610ace906142b7565b8660006011548261193591906143bb565b9050803410156119715760405162461bcd60e51b81526020600482015260076024820152660989eae408aa8960cb1b6044820152606401610ace565b8888888888838511156119b35760405162461bcd60e51b815260206004820152600a60248201526920a6a7aaa72a1022a92960b11b6044820152606401610ace565b600d5483146119f05760405162461bcd60e51b81526020600482015260096024820152682727a721a29022a92960b91b6044820152606401610ace565b600b547347a0915747565e8264296457b894068fe5ca91869063cffc18eb9061010090046001600160a01b0316611a25612308565b878787876040518763ffffffff1660e01b8152600401611a4a969594939291906142dd565b602060405180830381865afa158015611a67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8b9190614272565b611ac75760405162461bcd60e51b815260206004820152600d60248201526c29a4a3a720aa2aa9229022a92960991b6044820152606401610ace565b8385601b6000611ad5612308565b6001600160a01b03166001600160a01b0316815260200190815260200160002054611b00919061434f565b1115611b3a5760405162461bcd60e51b815260206004820152600960248201526821a620a4a69022a92960b91b6044820152606401610ace565b84601b6000611b47612308565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611b76919061434f565b9091555060009050611b8a8f611184612308565b9050611b97816000612e5f565b50506001600a8190559d9c50505050505050505050505050565b60006002600a5403611bd55760405162461bcd60e51b8152600401610ace90614367565b6002600a55600854600160a01b900460ff1615611c045760405162461bcd60e51b8152600401610ace9061420e565b600380601c5460ff166003811115611c1e57611c1e613f59565b1015611c3c5760405162461bcd60e51b8152600401610ace9061428f565b612755611c47610dba565b1115611c655760405162461bcd60e51b8152600401610ace906142b7565b82600060115482611c7691906143bb565b905080341015611cb25760405162461bcd60e51b81526020600482015260076024820152660989eae408aa8960cb1b6044820152606401610ace565b6000611cc086611184612308565b9050611ccd816000612e5f565b600194505050506001600a5550919050565b611ce7612308565b6001600160a01b0316826001600160a01b031603611d185760405163b06307db60e01b815260040160405180910390fd5b8060076000611d25612308565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155611d69612308565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611da5911515815260200190565b60405180910390a35050565b611db9612308565b6001600160a01b0316611dd46008546001600160a01b031690565b6001600160a01b031614611dfa5760405162461bcd60e51b8152600401610ace906141bd565b600e80546001600160a01b0319166001600160a01b0383169081179091556040517f62ff39aed768a426c7582b6e1062ab2631df1869b2d574e36f8274d2e2b0ab8190600090a250565b611e4f848484612552565b6001600160a01b0383163b15158015611e715750611e6f84848484612e90565b155b15611e8f576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b6060611ea0826124bd565b611ebd57604051630a14c4b560e41b815260040160405180910390fd5b6000611ec7612f81565b90508051600003611ee75760405180602001604052806000815250611f12565b80611ef184612f90565b604051602001611f029291906143da565b6040516020818303038152906040525b9392505050565b600854600160a01b900460ff1615611f435760405162461bcd60e51b8152600401610ace9061420e565b81611f4c612308565b6000828152601460205260409020546001600160a01b03908116911614611fa15760405162461bcd60e51b81526020600482015260096024820152681414950e914b4c4c0d60ba1b6044820152606401610ace565b82611fad610bfd612308565b611fe55760405162461bcd60e51b81526020600482015260096024820152685052543a452d31303560b81b6044820152606401610ace565b611e8f8484613091565b611ff7612308565b6001600160a01b03166120126008546001600160a01b031690565b6001600160a01b0316146120385760405162461bcd60e51b8152600401610ace906141bd565b600980546001600160a01b0319166001600160a01b03831617905550565b50565b612061612308565b6001600160a01b031661207c6008546001600160a01b031690565b6001600160a01b0316146120a25760405162461bcd60e51b8152600401610ace906141bd565b806120af57612056613114565b6120566131b7565b60006120c2826124bd565b61212d5760405162461bcd60e51b815260206004820152603660248201527f455243373231436f6e73756d61626c653a20636f6e73756d6572207175657279604482015275103337b9103737b732bc34b9ba32b73a103a37b5b2b760511b6064820152608401610ace565b506000908152601360205260409020546001600160a01b031690565b612151612308565b6001600160a01b031661216c6008546001600160a01b031690565b6001600160a01b0316146121925760405162461bcd60e51b8152600401610ace906141bd565b6001600160a01b0381166121f75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ace565b61205681612be3565b612208612308565b6001600160a01b03166122236008546001600160a01b031690565b6001600160a01b0316146122495760405162461bcd60e51b8152600401610ace906141bd565b60118190556040518181527f87e91c4015c3b3877a81d4e5876627cdee8f55f6a28b8452d1db91caf03eeceb9060200160405180910390a150565b6000601436108015906122a157506009546001600160a01b031633145b156122b3575060131936013560601c90565b503390565b60006001600160e01b031982166380ac58cd60e01b14806122e957506001600160e01b03198216635b5e139f60e01b145b80610a7f57506301ffc9a760e01b6001600160e01b0319831614610a7f565b6000612312612284565b905090565b6000612322826124bd565b6123835760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610ace565b600061238e83611501565b9050806001600160a01b0316846001600160a01b031614806123d557506001600160a01b0380821660009081526007602090815260408083209388168352929052205460ff165b806123f95750836001600160a01b03166123ee84610cdc565b6001600160a01b0316145b949350505050565b60008281526018602052604090819020829055600e549051636a5fcc8b60e11b81523060048201526024810184905282151560448201526001600160a01b039091169063d4bf991690606401600060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b50505050817fe23ea816dce6d7f5c0b85cbd597e7c3b97b2453791152c0b94e5e5c5f314d2f0826040516124b191815260200190565b60405180910390a25050565b6000816001111580156124d1575060005482105b8015610a7f575050600090815260046020526040902054600160e01b900460ff161590565b60008281526006602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600081815260186020526040808220829055600e549051636a5fcc8b60e11b81523060048201526024810184905260448101929092526001600160a01b03169063d4bf991690606401600060405180830381600087803b1580156125b557600080fd5b505af11580156125c9573d6000803e3d6000fd5b50505050610c4583838361321d565b6000806125e3610dba565b90506127556125f2858361434f565b11156126075761260481612755614409565b93505b612611838561343c565b60115461261e90856143bb565b915060008161262c81614420565b92505060005b858110156126a7578460146000612649848761434f565b8152602081019190915260400160002080546001600160a01b0319166001600160a01b0392909216919091179055612689612684828561434f565b613456565b612693908361434f565b91508061269f81614420565b915050612632565b506126d2826040518060400160405280600781526020016667656e6572696360c81b815250836134e9565b505092915050565b6001600160a01b0383166127005760405162461bcd60e51b8152600401610ace90614439565b6040516331a9108f60e11b81526004810182905230906001600160a01b03841690636352211e90602401602060405180830381865afa158015612747573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276b919061439e565b6001600160a01b031603610c45576040516323b872dd60e01b81523060048201526001600160a01b038481166024830152604482018390528316906323b872dd90606401600060405180830381600087803b1580156127c957600080fd5b505af11580156127dd573d6000803e3d6000fd5b5050505080826001600160a01b0316846001600160a01b03167ffefe036cac4ee3a4aca074a81cbcc4376e1484693289078dbec149c890101d5b60405160405180910390a4505050565b6001600160a01b03831661284d5760405162461bcd60e51b8152600401610ace90614439565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015612893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b7919061445c565b10610c45576128d06001600160a01b038316848361356d565b816001600160a01b0316836001600160a01b03167f6c9d637297625e945b296ff73a71fcfbd0a9e062652b6491a921c4c60194176b8360405161291591815260200190565b60405180910390a3505050565b6001600160a01b0382166129485760405162461bcd60e51b8152600401610ace90614439565b804710611490576129626001600160a01b038316826135bf565b816001600160a01b03167eddb683bb45cd5d0ad8a200c6fae7152b1c236ee90a4a37db692407f5cc38bd826040516124b191815260200190565b6001600160a01b038116600090815260176020526040812054806129ee5760405162461bcd60e51b81526020600482015260096024820152685052543a452d34313160b81b6044820152606401610ace565b6001600160a01b0383166000818152601760205260408120819055612a15919083906136d8565b826001600160a01b03167f8fbbda19f4a70036f6f585dc4160142a8fa2a20ffb9393d23274f78de4e3988882604051612a5091815260200190565b60405180910390a292915050565b60408051606081018252600080825260208201819052918101919091528180600111158015612a8e575060005481105b15612b6e57600081815260046020908152604091829020825160608101845290546001600160a01b0381168252600160a01b810467ffffffffffffffff1692820192909252600160e01b90910460ff16151591810182905290612b6c5780516001600160a01b031615612b02579392505050565b5060001901600081815260046020908152604091829020825160608101845290546001600160a01b038116808352600160a01b820467ffffffffffffffff1693830193909352600160e01b900460ff1615159281019290925215612b67579392505050565b612b02565b505b604051636f96cda160e11b815260040160405180910390fd5b60008181526013602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917f42ef856c2602f37ce625d252830bed486c5c8e9a4de8aa36cc3d15f304eb662b91a4505050565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000818152601660205260408120546001600160a01b031680610a7f5750506000908152601460205260409020546001600160a01b031690565b600082815260186020526040812054309184918190818082612cbf5760405162461bcd60e51b815260206004820152600960248201526828292a1d22969a189b60b91b6044820152606401610ace565b82341015612cfb5760405162461bcd60e51b81526020600482015260096024820152681414950e914b4d0c4d60ba1b6044820152606401610ace565b82612d058a611501565b9550612d0f612308565b9450612d1a8a612c35565b60008b815260156020908152604080832054601990925290912054919450908115801590612d485750600081115b8015612d5357508086115b15612d895761271082612d668389614409565b612d7091906143bb565b612d7a919061448b565b9350612d868484614409565b92505b60008c81526019602052604090208690558315612dce576001600160a01b03851660009081526017602052604081208054869290612dc890849061434f565b90915550505b612dd988888e612552565b604080518781526001600160a01b038781166020830152918101869052818916918a16908e907fdce0df8595dd59f5021b52ae75ffa131ac90c7c13a341bff14724f7921592a869060600160405180910390a48215612e4657612e466001600160a01b038916848d6136d8565b612e50868c612e5f565b50505092959891949750929550565b6000612e6b8334614409565b90508015610c4557610c458183612e80612308565b6001600160a01b031691906136d8565b6000836001600160a01b031663150b7a02612ea9612308565b8786866040518563ffffffff1660e01b8152600401612ecb949392919061449f565b6020604051808303816000875af1925050508015612f06575060408051601f3d908101601f19168201909252612f03918101906144dc565b60015b612f64573d808015612f34576040519150601f19603f3d011682016040523d82523d6000602084013e612f39565b606091505b508051600003612f5c576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b606060128054610c5990614238565b606081600003612fb75750506040805180820190915260018152600360fc1b602082015290565b8160005b8115612fe15780612fcb81614420565b9150612fda9050600a8361448b565b9150612fbb565b60008167ffffffffffffffff811115612ffc57612ffc613d80565b6040519080825280601f01601f191660200182016040528015613026576020820181803683370190505b5090505b84156123f95761303b600183614409565b9150613048600a866144f9565b61305390603061434f565b60f81b8183815181106130685761306861450d565b60200101906001600160f81b031916908160001a90535061308a600a8661448b565b945061302a565b611f408111156130cf5760405162461bcd60e51b81526020600482015260096024820152685052543a452d34323160b81b6044820152606401610ace565b600082815260156020526040908190208290555182907fd91bd92b973231f564eaa17c9bc62c86b96a8885f3cdcb990d5a3f0415580d90906124b19084815260200190565b600854600160a01b900460ff166131645760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ace565b6008805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61319a612308565b6040516001600160a01b03909116815260200160405180910390a1565b600854600160a01b900460ff16156131e15760405162461bcd60e51b8152600401610ace9061420e565b6008805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861319a612308565b600061322882612a5e565b9050836001600160a01b031681600001516001600160a01b03161461325f5760405162a1148160e81b815260040160405180910390fd5b6000846001600160a01b0316613273612308565b6001600160a01b0316148061328f575061328f856109bf612308565b806132ba575061329d612308565b6001600160a01b03166132af84610cdc565b6001600160a01b0316145b9050806132da57604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b03841661330157604051633a954ecd60e21b815260040160405180910390fd5b61330e858585600161384e565b61331a600084876124f6565b6001600160a01b038581166000908152600560209081526040808320805467ffffffffffffffff1980821667ffffffffffffffff92831660001901831617909255898616808652838620805493841693831660019081018416949094179055898652600490945282852080546001600160e01b031916909417600160a01b429092169190910217835587018084529220805491939091166133f05760005482146133f0578054602086015167ffffffffffffffff16600160a01b026001600160e01b03199091166001600160a01b038a16171781555b50505082846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b5050505050565b6114908282604051806020016040528060008152506138e2565b600061275582036134715750685684f3080793700000919050565b61232882111561348b5750684c0e894a96610c0000919050565b6117708211156134a55750683635c9adc5dea00000919050565b610bb88211156134bf5750685150ae84a8cdf00000919050565b6103e88211156134d95750685ede20f01a45980000919050565b5068878678326eac900000919050565b600f546010546040516305eef16560e11b815230926001600160a01b0390811692630bdde2ca9261352a9286928a928a929091169089908590600401614523565b6020604051808303816000875af1158015613549573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613435919061445c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610c459084906138ef565b8047101561360f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610ace565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461365c576040519150601f19603f3d011682016040523d82523d6000602084013e613661565b606091505b5050905080610c455760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610ace565b814710156137285760405162461bcd60e51b815260206004820152601f60248201527f546f6b656e496e666f3a20696e73756666696369656e742062616c616e6365006044820152606401610ace565b6000808211613785576040516001600160a01b038516908490600081818185875af1925050503d806000811461377a576040519150601f19603f3d011682016040523d82523d6000602084013e61377f565b606091505b506137d8565b6040516001600160a01b03851690839085906000818181858888f193505050503d80600081146137d1576040519150601f19603f3d011682016040523d82523d6000602084013e6137d6565b606091505b505b50905080611e8f5760405162461bcd60e51b815260206004820152603c60248201527f546f6b656e496e666f3a20756e61626c6520746f2073656e642076616c75652c60448201527f20726563697069656e74206d61792068617665207265766572746564000000006064820152608401610ace565b6001600160a01b03841615611e8f57600854600160a01b900460ff16156138cb5760405162461bcd60e51b815260206004820152602b60248201527f4552433732315061757361626c653a20746f6b656e207472616e73666572207760448201526a1a1a5b19481c185d5cd95960aa1b6064820152608401610ace565b600b5460ff1615611e8f57611e8f84600084612b87565b610c4583838360016139c1565b6000613944826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613ba09092919063ffffffff16565b805190915015610c4557808060200190518101906139629190614272565b610c455760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610ace565b6000546001600160a01b0385166139ea57604051622e076360e81b815260040160405180910390fd5b83600003613a0b5760405163b562e8dd60e01b815260040160405180910390fd5b613a18600086838761384e565b6001600160a01b038516600081815260056020908152604080832080546fffffffffffffffffffffffffffffffff19811667ffffffffffffffff8083168c0181169182176801000000000000000067ffffffffffffffff1990941690921783900481168c01811690920217909155858452600490925290912080546001600160e01b031916909217600160a01b429092169190910217905580808501838015613aca57506001600160a01b0387163b15155b15613b52575b60405182906001600160a01b038916906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4613b1b6000888480600101955088612e90565b613b38576040516368d2bf6b60e11b815260040160405180910390fd5b808203613ad0578260005414613b4d57600080fd5b613b97565b5b6040516001830192906001600160a01b038916906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4808203613b53575b50600055613435565b60606123f98484600085856001600160a01b0385163b613c025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ace565b600080866001600160a01b03168587604051613c1e91906141f2565b60006040518083038185875af1925050503d8060008114613c5b576040519150601f19603f3d011682016040523d82523d6000602084013e613c60565b606091505b5091509150613c70828286613c7b565b979650505050505050565b60608315613c8a575081611f12565b825115613c9a5782518084602001fd5b8160405162461bcd60e51b8152600401610ace9190613f01565b828054613cc090614238565b90600052602060002090601f016020900481019282613ce25760008555613d28565b82601f10613cfb57805160ff1916838001178555613d28565b82800160010185558215613d28579182015b82811115613d28578251825591602001919060010190613d0d565b50613d34929150613d38565b5090565b5b80821115613d345760008155600101613d39565b6001600160e01b03198116811461205657600080fd5b600060208284031215613d7557600080fd5b8135611f1281613d4d565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115613db157613db1613d80565b604051601f8501601f19908116603f01168101908282118183101715613dd957613dd9613d80565b81604052809350858152868686011115613df257600080fd5b858560208301376000602087830101525050509392505050565b600060208284031215613e1e57600080fd5b813567ffffffffffffffff811115613e3557600080fd5b8201601f81018413613e4657600080fd5b6123f984823560208401613d96565b6001600160a01b038116811461205657600080fd5b600060208284031215613e7c57600080fd5b8135611f1281613e55565b60008060408385031215613e9a57600080fd5b50508035926020909101359150565b60005b83811015613ec4578181015183820152602001613eac565b83811115611e8f5750506000910152565b60008151808452613eed816020860160208601613ea9565b601f01601f19169290920160200192915050565b602081526000611f126020830184613ed5565b600060208284031215613f2657600080fd5b5035919050565b60008060408385031215613f4057600080fd5b8235613f4b81613e55565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b6020810160048310613f9157634e487b7160e01b600052602160045260246000fd5b91905290565b600080600060608486031215613fac57600080fd5b8335613fb781613e55565b92506020840135613fc781613e55565b929592945050506040919091013590565b600080600080600060808688031215613ff057600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8082111561401d57600080fd5b818801915088601f83011261403157600080fd5b81358181111561404057600080fd5b89602082850101111561405257600080fd5b9699959850939650602001949392505050565b6000806040838503121561407857600080fd5b82359150602083013561408a81613e55565b809150509250929050565b6000602082840312156140a757600080fd5b813560048110611f1257600080fd5b801515811461205657600080fd5b6000602082840312156140d657600080fd5b8135611f12816140b6565b600080604083850312156140f457600080fd5b82356140ff81613e55565b9150602083013561408a816140b6565b6000806000806080858703121561412557600080fd5b843561413081613e55565b9350602085013561414081613e55565b925060408501359150606085013567ffffffffffffffff81111561416357600080fd5b8501601f8101871361417457600080fd5b61418387823560208401613d96565b91505092959194509250565b600080604083850312156141a257600080fd5b82356141ad81613e55565b9150602083013561408a81613e55565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60008251614204818460208701613ea9565b9190910192915050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b600181811c9082168061424c57607f821691505b60208210810361426c57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561428457600080fd5b8151611f12816140b6565b6020808252600e908201526d26a4a72a10282420a9a29022a92960911b604082015260600190565b6020808252600c908201526b14d55414131648131253525560a21b604082015260600190565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561436257614362614339565b500190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6000602082840312156143b057600080fd5b8151611f1281613e55565b60008160001904831182151516156143d5576143d5614339565b500290565b600083516143ec818460208801613ea9565b835190830190614400818360208801613ea9565b01949350505050565b60008282101561441b5761441b614339565b500390565b60006001820161443257614432614339565b5060010190565b6020808252600990820152684248503a452d34303360b81b604082015260600190565b60006020828403121561446e57600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b60008261449a5761449a614475565b500490565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906144d290830184613ed5565b9695505050505050565b6000602082840312156144ee57600080fd5b8151611f1281613d4d565b60008261450857614508614475565b500690565b634e487b7160e01b600052603260045260246000fd5b600060018060a01b03808916835287602084015260c0604084015261454b60c0840188613ed5565b9581166060840152608083019490945250911660a090910152939250505056fe312e302e302d626574612e312f636861726765642d7061727469636c65732e72656c61792e726563697069656e74a2646970667358221220ca5d34997d0bcb7d02d6521d8dba33d9fdfbb35791cf0bb0142a9c4543586c1a64736f6c634300080d0033697066733a2f2f516d51726447316345537242656e4e5561546d78636b466d34674a77674c646b715447784e4c7568347435766f382f

Deployed Bytecode

0x6080604052600436106103355760003560e01c80636e5559fd116101ab578063a0712d68116100f7578063da74222811610095578063e985e9c51161006f578063e985e9c5146109a4578063f2fde38b146109ed578063f4a0a52814610a0d578063f8eb5fc514610a2d57600080fd5b8063da74222814610944578063db9f60ff14610964578063e58923311461098457600080fd5b8063b7683e93116100d1578063b7683e93146108c4578063b88d4fde146108e4578063c87b56dd14610904578063c8c680d51461092457600080fd5b8063a0712d6814610864578063a22cb46514610877578063ad82c42c1461089757600080fd5b80637987df1711610164578063846ec08c1161013e578063846ec08c146107e85780638da5cb5b1461081e57806395d89b411461083c57806397b36dc51461085157600080fd5b80637987df171461078e5780637c5e2795146107ae5780637da0a877146107ca57600080fd5b80636e5559fd146106e657806370a082311461070657806370b5aecb14610726578063715018a61461074657806371e715f41461075b57806371ecfcb31461077b57600080fd5b80632fc7779711610285578063486ff0cd11610223578063589a1743116101fd578063589a17431461065c5780635c975abb146106925780636348af34146106b15780636352211e146106c657600080fd5b8063486ff0cd146105f8578063522f68151461060d578063572b6c051461062d57600080fd5b80634025feb21161025f5780634025feb21461057857806342842e0e1461059857806344004cc1146105b857806346aa05b0146105d857600080fd5b80632fc777971461052257806331c07bbf1461054257806332cb6b0c1461056257600080fd5b8063095ea7b3116102f257806323b872dd116102cc57806323b872dd14610495578063250b2c80146104b557806326bde5aa146104e25780632d1465dd1461050257600080fd5b8063095ea7b31461042b57806317881cbf1461044b57806318160ddd1461047257600080fd5b806301ffc9a71461033a57806302fe53051461036f578063046dc16614610391578063053992c5146103b157806306fdde03146103d1578063081812fc146103f3575b600080fd5b34801561034657600080fd5b5061035a610355366004613d63565b610a5a565b60405190151581526020015b60405180910390f35b34801561037b57600080fd5b5061038f61038a366004613e0c565b610a85565b005b34801561039d57600080fd5b5061038f6103ac366004613e6a565b610b2c565b3480156103bd57600080fd5b5061038f6103cc366004613e87565b610bc7565b3480156103dd57600080fd5b506103e6610c4a565b6040516103669190613f01565b3480156103ff57600080fd5b5061041361040e366004613f14565b610cdc565b6040516001600160a01b039091168152602001610366565b34801561043757600080fd5b5061038f610446366004613f2d565b610d20565b34801561045757600080fd5b50601c546104659060ff1681565b6040516103669190613f6f565b34801561047e57600080fd5b50610487610dba565b604051908152602001610366565b3480156104a157600080fd5b5061038f6104b0366004613f97565b610dc8565b3480156104c157600080fd5b506104876104d0366004613f14565b60009081526019602052604090205490565b3480156104ee57600080fd5b5061038f6104fd366004613e6a565b610dd3565b34801561050e57600080fd5b5061035a61051d366004613fd8565b610edf565b34801561052e57600080fd5b5061038f61053d366004614065565b61119c565b34801561054e57600080fd5b5061038f61055d366004614095565b611253565b34801561056e57600080fd5b5061048761275581565b34801561058457600080fd5b5061038f610593366004613f97565b6112fe565b3480156105a457600080fd5b5061038f6105b3366004613f97565b611352565b3480156105c457600080fd5b5061038f6105d3366004613f97565b61136d565b3480156105e457600080fd5b5061038f6105f33660046140c4565b6113c1565b34801561060457600080fd5b506103e661141d565b34801561061957600080fd5b5061038f610628366004613f2d565b61143d565b34801561063957600080fd5b5061035a610648366004613e6a565b6009546001600160a01b0391821691161490565b34801561066857600080fd5b50610413610677366004613f14565b6000908152601460205260409020546001600160a01b031690565b34801561069e57600080fd5b50600854600160a01b900460ff1661035a565b3480156106bd57600080fd5b50610487611494565b3480156106d257600080fd5b506104136106e1366004613f14565b611501565b3480156106f257600080fd5b5061038f610701366004613e6a565b611513565b34801561071257600080fd5b50610487610721366004613e6a565b6115a6565b34801561073257600080fd5b5061038f610741366004613f2d565b6115f5565b34801561075257600080fd5b5061038f61173a565b34801561076757600080fd5b50610413610776366004613f14565b61178f565b61035a610789366004613e87565b61179a565b34801561079a57600080fd5b5061038f6107a9366004613e87565b61180d565b3480156107ba57600080fd5b50610487670214e8348c4f000081565b3480156107d657600080fd5b506009546001600160a01b0316610413565b3480156107f457600080fd5b50610487610803366004613e6a565b6001600160a01b031660009081526017602052604090205490565b34801561082a57600080fd5b506008546001600160a01b0316610413565b34801561084857600080fd5b506103e6611861565b61035a61085f366004613fd8565b611870565b61035a610872366004613f14565b611bb1565b34801561088357600080fd5b5061038f6108923660046140e1565b611cdf565b3480156108a357600080fd5b506104876108b2366004613f14565b60009081526015602052604090205490565b3480156108d057600080fd5b5061038f6108df366004613e6a565b611db1565b3480156108f057600080fd5b5061038f6108ff36600461410f565b611e44565b34801561091057600080fd5b506103e661091f366004613f14565b611e95565b34801561093057600080fd5b5061038f61093f366004613e87565b611f19565b34801561095057600080fd5b5061038f61095f366004613e6a565b611fef565b34801561097057600080fd5b5061038f61097f3660046140c4565b612059565b34801561099057600080fd5b5061041361099f366004613f14565b6120b7565b3480156109b057600080fd5b5061035a6109bf36600461418f565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b3480156109f957600080fd5b5061038f610a08366004613e6a565b612149565b348015610a1957600080fd5b5061038f610a28366004613f14565b612200565b348015610a3957600080fd5b50610487610a48366004613f14565b60009081526018602052604090205490565b60006001600160e01b03198216634a9e46fd60e11b1480610a7f5750610a7f826122b8565b92915050565b610a8d612308565b6001600160a01b0316610aa86008546001600160a01b031690565b6001600160a01b031614610ad75760405162461bcd60e51b8152600401610ace906141bd565b60405180910390fd5b8051610aea906012906020840190613cb4565b5080604051610af991906141f2565b604051908190038120907f325d37e8fb549c86966f09bc3e6f62eb3afa93b255d6e3234338001f3d80bd8690600090a250565b610b34612308565b6001600160a01b0316610b4f6008546001600160a01b031690565b6001600160a01b031614610b755760405162461bcd60e51b8152600401610ace906141bd565b600b8054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517fee8162dfe409d975b252297226f4d86a293dbeecb9e3c5e64b837dd2758509e290600090a250565b600854600160a01b900460ff1615610bf15760405162461bcd60e51b8152600401610ace9061420e565b81610c03610bfd612308565b82612317565b610c3b5760405162461bcd60e51b81526020600482015260096024820152685052543a452d31303560b81b6044820152606401610ace565b610c458383612401565b505050565b606060028054610c5990614238565b80601f0160208091040260200160405190810160405280929190818152602001828054610c8590614238565b8015610cd25780601f10610ca757610100808354040283529160200191610cd2565b820191906000526020600020905b815481529060010190602001808311610cb557829003601f168201915b5050505050905090565b6000610ce7826124bd565b610d04576040516333d1c03960e21b815260040160405180910390fd5b506000908152600660205260409020546001600160a01b031690565b6000610d2b82611501565b9050806001600160a01b0316836001600160a01b031603610d5f5760405163250fdee360e21b815260040160405180910390fd5b806001600160a01b0316610d71612308565b6001600160a01b031614158015610d915750610d8f816109bf612308565b155b15610daf576040516367d9dca160e11b815260040160405180910390fd5b610c458383836124f6565b600154600054036000190190565b610c45838383612552565b610ddb612308565b6001600160a01b0316610df66008546001600160a01b031690565b6001600160a01b031614610e1c5760405162461bcd60e51b8152600401610ace906141bd565b601080546001600160a01b0319166001600160a01b03838116918217909255600f5460405163095ea7b360e01b81529216600483015260001960248301529063095ea7b3906044016020604051808303816000875af1158015610e83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea79190614272565b506040516001600160a01b038216907fbdaa8f7ade01473981aef419539e6c190d409f50b144a7a796efd2777607920c90600090a250565b600854600090600160a01b900460ff1615610f0c5760405162461bcd60e51b8152600401610ace9061420e565b600180601c5460ff166003811115610f2657610f26613f59565b1015610f445760405162461bcd60e51b8152600401610ace9061428f565b612755610f4f610dba565b1115610f6d5760405162461bcd60e51b8152600401610ace906142b7565b868686868683851115610faf5760405162461bcd60e51b815260206004820152600a60248201526920a6a7aaa72a1022a92960b11b6044820152606401610ace565b600c548314610fec5760405162461bcd60e51b81526020600482015260096024820152682727a721a29022a92960b91b6044820152606401610ace565b600b547347a0915747565e8264296457b894068fe5ca91869063cffc18eb9061010090046001600160a01b0316611021612308565b878787876040518763ffffffff1660e01b8152600401611046969594939291906142dd565b602060405180830381865afa158015611063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110879190614272565b6110c35760405162461bcd60e51b815260206004820152600d60248201526c29a4a3a720aa2aa9229022a92960991b6044820152606401610ace565b8385601a60006110d1612308565b6001600160a01b03166001600160a01b03168152602001908152602001600020546110fc919061434f565b11156111365760405162461bcd60e51b815260206004820152600960248201526821a620a4a69022a92960b91b6044820152606401610ace565b84601a6000611143612308565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611172919061434f565b9091555061118990508c611184612308565b6125d8565b5060019c9b505050505050505050505050565b600854600160a01b900460ff16156111c65760405162461bcd60e51b8152600401610ace9061420e565b816111cf612308565b6000828152601460205260409020546001600160a01b039081169116146112245760405162461bcd60e51b81526020600482015260096024820152681414950e914b4c4c0d60ba1b6044820152606401610ace565b5060009182526016602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b61125b612308565b6001600160a01b03166112766008546001600160a01b031690565b6001600160a01b03161461129c5760405162461bcd60e51b8152600401610ace906141bd565b601c805482919060ff191660018360038111156112bb576112bb613f59565b02179055508060038111156112d2576112d2613f59565b6040517fcae7e973d86fb577229be71728483bccd6ca3b5c5bf6ad354c31e6482455c4f090600090a250565b611306612308565b6001600160a01b03166113216008546001600160a01b031690565b6001600160a01b0316146113475760405162461bcd60e51b8152600401610ace906141bd565b610c458383836126da565b610c4583838360405180602001604052806000815250611e44565b611375612308565b6001600160a01b03166113906008546001600160a01b031690565b6001600160a01b0316146113b65760405162461bcd60e51b8152600401610ace906141bd565b610c45838383612827565b6113c9612308565b6001600160a01b03166113e46008546001600160a01b031690565b6001600160a01b03161461140a5760405162461bcd60e51b8152600401610ace906141bd565b600b805460ff1916911515919091179055565b60606040518060600160405280602e815260200161456c602e9139905090565b611445612308565b6001600160a01b03166114606008546001600160a01b031690565b6001600160a01b0316146114865760405162461bcd60e51b8152600401610ace906141bd565b6114908282612922565b5050565b60006002600a54036114b85760405162461bcd60e51b8152600401610ace90614367565b6002600a55600854600160a01b900460ff16156114e75760405162461bcd60e51b8152600401610ace9061420e565b6114f76114f2612308565b61299c565b90506001600a5590565b600061150c82612a5e565b5192915050565b61151b612308565b6001600160a01b03166115366008546001600160a01b031690565b6001600160a01b03161461155c5760405162461bcd60e51b8152600401610ace906141bd565b600f80546001600160a01b0319166001600160a01b0383169081179091556040517f5ce0e6b7fd36339ee97339831b6c72694ecee88c62aab49919d9cabe0a732e4190600090a250565b60006001600160a01b0382166115cf576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526005602052604090205467ffffffffffffffff1690565b6040516331a9108f60e11b8152600481018290526000903090636352211e90602401602060405180830381865afa158015611634573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611658919061439e565b9050806001600160a01b031661166c612308565b6001600160a01b031614806116a1575061168582610cdc565b6001600160a01b0316611696612308565b6001600160a01b0316145b806116b357506116b3816109bf612308565b61172f5760405162461bcd60e51b815260206004820152604160248201527f455243373231436f6e73756d61626c653a206368616e6765436f6e73756d657260448201527f2063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656064820152601960fa1b608482015260a401610ace565b610c45818484612b87565b611742612308565b6001600160a01b031661175d6008546001600160a01b031690565b6001600160a01b0316146117835760405162461bcd60e51b8152600401610ace906141bd565b61178d6000612be3565b565b6000610a7f82612c35565b60006002600a54036117be5760405162461bcd60e51b8152600401610ace90614367565b6002600a55600854600160a01b900460ff16156117ed5760405162461bcd60e51b8152600401610ace9061420e565b6117f78383612c6f565b50505050505050600190506001600a5592915050565b611815612308565b6001600160a01b03166118306008546001600160a01b031690565b6001600160a01b0316146118565760405162461bcd60e51b8152600401610ace906141bd565b600c91909155600d55565b606060038054610c5990614238565b60006002600a54036118945760405162461bcd60e51b8152600401610ace90614367565b6002600a55600854600160a01b900460ff16156118c35760405162461bcd60e51b8152600401610ace9061420e565b600280601c5460ff1660038111156118dd576118dd613f59565b10156118fb5760405162461bcd60e51b8152600401610ace9061428f565b612755611906610dba565b11156119245760405162461bcd60e51b8152600401610ace906142b7565b8660006011548261193591906143bb565b9050803410156119715760405162461bcd60e51b81526020600482015260076024820152660989eae408aa8960cb1b6044820152606401610ace565b8888888888838511156119b35760405162461bcd60e51b815260206004820152600a60248201526920a6a7aaa72a1022a92960b11b6044820152606401610ace565b600d5483146119f05760405162461bcd60e51b81526020600482015260096024820152682727a721a29022a92960b91b6044820152606401610ace565b600b547347a0915747565e8264296457b894068fe5ca91869063cffc18eb9061010090046001600160a01b0316611a25612308565b878787876040518763ffffffff1660e01b8152600401611a4a969594939291906142dd565b602060405180830381865afa158015611a67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8b9190614272565b611ac75760405162461bcd60e51b815260206004820152600d60248201526c29a4a3a720aa2aa9229022a92960991b6044820152606401610ace565b8385601b6000611ad5612308565b6001600160a01b03166001600160a01b0316815260200190815260200160002054611b00919061434f565b1115611b3a5760405162461bcd60e51b815260206004820152600960248201526821a620a4a69022a92960b91b6044820152606401610ace565b84601b6000611b47612308565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611b76919061434f565b9091555060009050611b8a8f611184612308565b9050611b97816000612e5f565b50506001600a8190559d9c50505050505050505050505050565b60006002600a5403611bd55760405162461bcd60e51b8152600401610ace90614367565b6002600a55600854600160a01b900460ff1615611c045760405162461bcd60e51b8152600401610ace9061420e565b600380601c5460ff166003811115611c1e57611c1e613f59565b1015611c3c5760405162461bcd60e51b8152600401610ace9061428f565b612755611c47610dba565b1115611c655760405162461bcd60e51b8152600401610ace906142b7565b82600060115482611c7691906143bb565b905080341015611cb25760405162461bcd60e51b81526020600482015260076024820152660989eae408aa8960cb1b6044820152606401610ace565b6000611cc086611184612308565b9050611ccd816000612e5f565b600194505050506001600a5550919050565b611ce7612308565b6001600160a01b0316826001600160a01b031603611d185760405163b06307db60e01b815260040160405180910390fd5b8060076000611d25612308565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155611d69612308565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611da5911515815260200190565b60405180910390a35050565b611db9612308565b6001600160a01b0316611dd46008546001600160a01b031690565b6001600160a01b031614611dfa5760405162461bcd60e51b8152600401610ace906141bd565b600e80546001600160a01b0319166001600160a01b0383169081179091556040517f62ff39aed768a426c7582b6e1062ab2631df1869b2d574e36f8274d2e2b0ab8190600090a250565b611e4f848484612552565b6001600160a01b0383163b15158015611e715750611e6f84848484612e90565b155b15611e8f576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b6060611ea0826124bd565b611ebd57604051630a14c4b560e41b815260040160405180910390fd5b6000611ec7612f81565b90508051600003611ee75760405180602001604052806000815250611f12565b80611ef184612f90565b604051602001611f029291906143da565b6040516020818303038152906040525b9392505050565b600854600160a01b900460ff1615611f435760405162461bcd60e51b8152600401610ace9061420e565b81611f4c612308565b6000828152601460205260409020546001600160a01b03908116911614611fa15760405162461bcd60e51b81526020600482015260096024820152681414950e914b4c4c0d60ba1b6044820152606401610ace565b82611fad610bfd612308565b611fe55760405162461bcd60e51b81526020600482015260096024820152685052543a452d31303560b81b6044820152606401610ace565b611e8f8484613091565b611ff7612308565b6001600160a01b03166120126008546001600160a01b031690565b6001600160a01b0316146120385760405162461bcd60e51b8152600401610ace906141bd565b600980546001600160a01b0319166001600160a01b03831617905550565b50565b612061612308565b6001600160a01b031661207c6008546001600160a01b031690565b6001600160a01b0316146120a25760405162461bcd60e51b8152600401610ace906141bd565b806120af57612056613114565b6120566131b7565b60006120c2826124bd565b61212d5760405162461bcd60e51b815260206004820152603660248201527f455243373231436f6e73756d61626c653a20636f6e73756d6572207175657279604482015275103337b9103737b732bc34b9ba32b73a103a37b5b2b760511b6064820152608401610ace565b506000908152601360205260409020546001600160a01b031690565b612151612308565b6001600160a01b031661216c6008546001600160a01b031690565b6001600160a01b0316146121925760405162461bcd60e51b8152600401610ace906141bd565b6001600160a01b0381166121f75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ace565b61205681612be3565b612208612308565b6001600160a01b03166122236008546001600160a01b031690565b6001600160a01b0316146122495760405162461bcd60e51b8152600401610ace906141bd565b60118190556040518181527f87e91c4015c3b3877a81d4e5876627cdee8f55f6a28b8452d1db91caf03eeceb9060200160405180910390a150565b6000601436108015906122a157506009546001600160a01b031633145b156122b3575060131936013560601c90565b503390565b60006001600160e01b031982166380ac58cd60e01b14806122e957506001600160e01b03198216635b5e139f60e01b145b80610a7f57506301ffc9a760e01b6001600160e01b0319831614610a7f565b6000612312612284565b905090565b6000612322826124bd565b6123835760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610ace565b600061238e83611501565b9050806001600160a01b0316846001600160a01b031614806123d557506001600160a01b0380821660009081526007602090815260408083209388168352929052205460ff165b806123f95750836001600160a01b03166123ee84610cdc565b6001600160a01b0316145b949350505050565b60008281526018602052604090819020829055600e549051636a5fcc8b60e11b81523060048201526024810184905282151560448201526001600160a01b039091169063d4bf991690606401600060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b50505050817fe23ea816dce6d7f5c0b85cbd597e7c3b97b2453791152c0b94e5e5c5f314d2f0826040516124b191815260200190565b60405180910390a25050565b6000816001111580156124d1575060005482105b8015610a7f575050600090815260046020526040902054600160e01b900460ff161590565b60008281526006602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600081815260186020526040808220829055600e549051636a5fcc8b60e11b81523060048201526024810184905260448101929092526001600160a01b03169063d4bf991690606401600060405180830381600087803b1580156125b557600080fd5b505af11580156125c9573d6000803e3d6000fd5b50505050610c4583838361321d565b6000806125e3610dba565b90506127556125f2858361434f565b11156126075761260481612755614409565b93505b612611838561343c565b60115461261e90856143bb565b915060008161262c81614420565b92505060005b858110156126a7578460146000612649848761434f565b8152602081019190915260400160002080546001600160a01b0319166001600160a01b0392909216919091179055612689612684828561434f565b613456565b612693908361434f565b91508061269f81614420565b915050612632565b506126d2826040518060400160405280600781526020016667656e6572696360c81b815250836134e9565b505092915050565b6001600160a01b0383166127005760405162461bcd60e51b8152600401610ace90614439565b6040516331a9108f60e11b81526004810182905230906001600160a01b03841690636352211e90602401602060405180830381865afa158015612747573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276b919061439e565b6001600160a01b031603610c45576040516323b872dd60e01b81523060048201526001600160a01b038481166024830152604482018390528316906323b872dd90606401600060405180830381600087803b1580156127c957600080fd5b505af11580156127dd573d6000803e3d6000fd5b5050505080826001600160a01b0316846001600160a01b03167ffefe036cac4ee3a4aca074a81cbcc4376e1484693289078dbec149c890101d5b60405160405180910390a4505050565b6001600160a01b03831661284d5760405162461bcd60e51b8152600401610ace90614439565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015612893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b7919061445c565b10610c45576128d06001600160a01b038316848361356d565b816001600160a01b0316836001600160a01b03167f6c9d637297625e945b296ff73a71fcfbd0a9e062652b6491a921c4c60194176b8360405161291591815260200190565b60405180910390a3505050565b6001600160a01b0382166129485760405162461bcd60e51b8152600401610ace90614439565b804710611490576129626001600160a01b038316826135bf565b816001600160a01b03167eddb683bb45cd5d0ad8a200c6fae7152b1c236ee90a4a37db692407f5cc38bd826040516124b191815260200190565b6001600160a01b038116600090815260176020526040812054806129ee5760405162461bcd60e51b81526020600482015260096024820152685052543a452d34313160b81b6044820152606401610ace565b6001600160a01b0383166000818152601760205260408120819055612a15919083906136d8565b826001600160a01b03167f8fbbda19f4a70036f6f585dc4160142a8fa2a20ffb9393d23274f78de4e3988882604051612a5091815260200190565b60405180910390a292915050565b60408051606081018252600080825260208201819052918101919091528180600111158015612a8e575060005481105b15612b6e57600081815260046020908152604091829020825160608101845290546001600160a01b0381168252600160a01b810467ffffffffffffffff1692820192909252600160e01b90910460ff16151591810182905290612b6c5780516001600160a01b031615612b02579392505050565b5060001901600081815260046020908152604091829020825160608101845290546001600160a01b038116808352600160a01b820467ffffffffffffffff1693830193909352600160e01b900460ff1615159281019290925215612b67579392505050565b612b02565b505b604051636f96cda160e11b815260040160405180910390fd5b60008181526013602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917f42ef856c2602f37ce625d252830bed486c5c8e9a4de8aa36cc3d15f304eb662b91a4505050565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000818152601660205260408120546001600160a01b031680610a7f5750506000908152601460205260409020546001600160a01b031690565b600082815260186020526040812054309184918190818082612cbf5760405162461bcd60e51b815260206004820152600960248201526828292a1d22969a189b60b91b6044820152606401610ace565b82341015612cfb5760405162461bcd60e51b81526020600482015260096024820152681414950e914b4d0c4d60ba1b6044820152606401610ace565b82612d058a611501565b9550612d0f612308565b9450612d1a8a612c35565b60008b815260156020908152604080832054601990925290912054919450908115801590612d485750600081115b8015612d5357508086115b15612d895761271082612d668389614409565b612d7091906143bb565b612d7a919061448b565b9350612d868484614409565b92505b60008c81526019602052604090208690558315612dce576001600160a01b03851660009081526017602052604081208054869290612dc890849061434f565b90915550505b612dd988888e612552565b604080518781526001600160a01b038781166020830152918101869052818916918a16908e907fdce0df8595dd59f5021b52ae75ffa131ac90c7c13a341bff14724f7921592a869060600160405180910390a48215612e4657612e466001600160a01b038916848d6136d8565b612e50868c612e5f565b50505092959891949750929550565b6000612e6b8334614409565b90508015610c4557610c458183612e80612308565b6001600160a01b031691906136d8565b6000836001600160a01b031663150b7a02612ea9612308565b8786866040518563ffffffff1660e01b8152600401612ecb949392919061449f565b6020604051808303816000875af1925050508015612f06575060408051601f3d908101601f19168201909252612f03918101906144dc565b60015b612f64573d808015612f34576040519150601f19603f3d011682016040523d82523d6000602084013e612f39565b606091505b508051600003612f5c576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b606060128054610c5990614238565b606081600003612fb75750506040805180820190915260018152600360fc1b602082015290565b8160005b8115612fe15780612fcb81614420565b9150612fda9050600a8361448b565b9150612fbb565b60008167ffffffffffffffff811115612ffc57612ffc613d80565b6040519080825280601f01601f191660200182016040528015613026576020820181803683370190505b5090505b84156123f95761303b600183614409565b9150613048600a866144f9565b61305390603061434f565b60f81b8183815181106130685761306861450d565b60200101906001600160f81b031916908160001a90535061308a600a8661448b565b945061302a565b611f408111156130cf5760405162461bcd60e51b81526020600482015260096024820152685052543a452d34323160b81b6044820152606401610ace565b600082815260156020526040908190208290555182907fd91bd92b973231f564eaa17c9bc62c86b96a8885f3cdcb990d5a3f0415580d90906124b19084815260200190565b600854600160a01b900460ff166131645760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ace565b6008805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61319a612308565b6040516001600160a01b03909116815260200160405180910390a1565b600854600160a01b900460ff16156131e15760405162461bcd60e51b8152600401610ace9061420e565b6008805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861319a612308565b600061322882612a5e565b9050836001600160a01b031681600001516001600160a01b03161461325f5760405162a1148160e81b815260040160405180910390fd5b6000846001600160a01b0316613273612308565b6001600160a01b0316148061328f575061328f856109bf612308565b806132ba575061329d612308565b6001600160a01b03166132af84610cdc565b6001600160a01b0316145b9050806132da57604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b03841661330157604051633a954ecd60e21b815260040160405180910390fd5b61330e858585600161384e565b61331a600084876124f6565b6001600160a01b038581166000908152600560209081526040808320805467ffffffffffffffff1980821667ffffffffffffffff92831660001901831617909255898616808652838620805493841693831660019081018416949094179055898652600490945282852080546001600160e01b031916909417600160a01b429092169190910217835587018084529220805491939091166133f05760005482146133f0578054602086015167ffffffffffffffff16600160a01b026001600160e01b03199091166001600160a01b038a16171781555b50505082846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b5050505050565b6114908282604051806020016040528060008152506138e2565b600061275582036134715750685684f3080793700000919050565b61232882111561348b5750684c0e894a96610c0000919050565b6117708211156134a55750683635c9adc5dea00000919050565b610bb88211156134bf5750685150ae84a8cdf00000919050565b6103e88211156134d95750685ede20f01a45980000919050565b5068878678326eac900000919050565b600f546010546040516305eef16560e11b815230926001600160a01b0390811692630bdde2ca9261352a9286928a928a929091169089908590600401614523565b6020604051808303816000875af1158015613549573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613435919061445c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610c459084906138ef565b8047101561360f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610ace565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461365c576040519150601f19603f3d011682016040523d82523d6000602084013e613661565b606091505b5050905080610c455760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610ace565b814710156137285760405162461bcd60e51b815260206004820152601f60248201527f546f6b656e496e666f3a20696e73756666696369656e742062616c616e6365006044820152606401610ace565b6000808211613785576040516001600160a01b038516908490600081818185875af1925050503d806000811461377a576040519150601f19603f3d011682016040523d82523d6000602084013e61377f565b606091505b506137d8565b6040516001600160a01b03851690839085906000818181858888f193505050503d80600081146137d1576040519150601f19603f3d011682016040523d82523d6000602084013e6137d6565b606091505b505b50905080611e8f5760405162461bcd60e51b815260206004820152603c60248201527f546f6b656e496e666f3a20756e61626c6520746f2073656e642076616c75652c60448201527f20726563697069656e74206d61792068617665207265766572746564000000006064820152608401610ace565b6001600160a01b03841615611e8f57600854600160a01b900460ff16156138cb5760405162461bcd60e51b815260206004820152602b60248201527f4552433732315061757361626c653a20746f6b656e207472616e73666572207760448201526a1a1a5b19481c185d5cd95960aa1b6064820152608401610ace565b600b5460ff1615611e8f57611e8f84600084612b87565b610c4583838360016139c1565b6000613944826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613ba09092919063ffffffff16565b805190915015610c4557808060200190518101906139629190614272565b610c455760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610ace565b6000546001600160a01b0385166139ea57604051622e076360e81b815260040160405180910390fd5b83600003613a0b5760405163b562e8dd60e01b815260040160405180910390fd5b613a18600086838761384e565b6001600160a01b038516600081815260056020908152604080832080546fffffffffffffffffffffffffffffffff19811667ffffffffffffffff8083168c0181169182176801000000000000000067ffffffffffffffff1990941690921783900481168c01811690920217909155858452600490925290912080546001600160e01b031916909217600160a01b429092169190910217905580808501838015613aca57506001600160a01b0387163b15155b15613b52575b60405182906001600160a01b038916906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4613b1b6000888480600101955088612e90565b613b38576040516368d2bf6b60e11b815260040160405180910390fd5b808203613ad0578260005414613b4d57600080fd5b613b97565b5b6040516001830192906001600160a01b038916906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4808203613b53575b50600055613435565b60606123f98484600085856001600160a01b0385163b613c025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ace565b600080866001600160a01b03168587604051613c1e91906141f2565b60006040518083038185875af1925050503d8060008114613c5b576040519150601f19603f3d011682016040523d82523d6000602084013e613c60565b606091505b5091509150613c70828286613c7b565b979650505050505050565b60608315613c8a575081611f12565b825115613c9a5782518084602001fd5b8160405162461bcd60e51b8152600401610ace9190613f01565b828054613cc090614238565b90600052602060002090601f016020900481019282613ce25760008555613d28565b82601f10613cfb57805160ff1916838001178555613d28565b82800160010185558215613d28579182015b82811115613d28578251825591602001919060010190613d0d565b50613d34929150613d38565b5090565b5b80821115613d345760008155600101613d39565b6001600160e01b03198116811461205657600080fd5b600060208284031215613d7557600080fd5b8135611f1281613d4d565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115613db157613db1613d80565b604051601f8501601f19908116603f01168101908282118183101715613dd957613dd9613d80565b81604052809350858152868686011115613df257600080fd5b858560208301376000602087830101525050509392505050565b600060208284031215613e1e57600080fd5b813567ffffffffffffffff811115613e3557600080fd5b8201601f81018413613e4657600080fd5b6123f984823560208401613d96565b6001600160a01b038116811461205657600080fd5b600060208284031215613e7c57600080fd5b8135611f1281613e55565b60008060408385031215613e9a57600080fd5b50508035926020909101359150565b60005b83811015613ec4578181015183820152602001613eac565b83811115611e8f5750506000910152565b60008151808452613eed816020860160208601613ea9565b601f01601f19169290920160200192915050565b602081526000611f126020830184613ed5565b600060208284031215613f2657600080fd5b5035919050565b60008060408385031215613f4057600080fd5b8235613f4b81613e55565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b6020810160048310613f9157634e487b7160e01b600052602160045260246000fd5b91905290565b600080600060608486031215613fac57600080fd5b8335613fb781613e55565b92506020840135613fc781613e55565b929592945050506040919091013590565b600080600080600060808688031215613ff057600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8082111561401d57600080fd5b818801915088601f83011261403157600080fd5b81358181111561404057600080fd5b89602082850101111561405257600080fd5b9699959850939650602001949392505050565b6000806040838503121561407857600080fd5b82359150602083013561408a81613e55565b809150509250929050565b6000602082840312156140a757600080fd5b813560048110611f1257600080fd5b801515811461205657600080fd5b6000602082840312156140d657600080fd5b8135611f12816140b6565b600080604083850312156140f457600080fd5b82356140ff81613e55565b9150602083013561408a816140b6565b6000806000806080858703121561412557600080fd5b843561413081613e55565b9350602085013561414081613e55565b925060408501359150606085013567ffffffffffffffff81111561416357600080fd5b8501601f8101871361417457600080fd5b61418387823560208401613d96565b91505092959194509250565b600080604083850312156141a257600080fd5b82356141ad81613e55565b9150602083013561408a81613e55565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60008251614204818460208701613ea9565b9190910192915050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b600181811c9082168061424c57607f821691505b60208210810361426c57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561428457600080fd5b8151611f12816140b6565b6020808252600e908201526d26a4a72a10282420a9a29022a92960911b604082015260600190565b6020808252600c908201526b14d55414131648131253525560a21b604082015260600190565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561436257614362614339565b500190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6000602082840312156143b057600080fd5b8151611f1281613e55565b60008160001904831182151516156143d5576143d5614339565b500290565b600083516143ec818460208801613ea9565b835190830190614400818360208801613ea9565b01949350505050565b60008282101561441b5761441b614339565b500390565b60006001820161443257614432614339565b5060010190565b6020808252600990820152684248503a452d34303360b81b604082015260600190565b60006020828403121561446e57600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b60008261449a5761449a614475565b500490565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906144d290830184613ed5565b9695505050505050565b6000602082840312156144ee57600080fd5b8151611f1281613d4d565b60008261450857614508614475565b500690565b634e487b7160e01b600052603260045260246000fd5b600060018060a01b03808916835287602084015260c0604084015261454b60c0840188613ed5565b9581166060840152608083019490945250911660a090910152939250505056fe312e302e302d626574612e312f636861726765642d7061727469636c65732e72656c61792e726563697069656e74a2646970667358221220ca5d34997d0bcb7d02d6521d8dba33d9fdfbb35791cf0bb0142a9c4543586c1a64736f6c634300080d0033

Deployed Bytecode Sourcemap

91927:23709:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95176:284;;;;;;;;;;-1:-1:-1;95176:284:0;;;;;:::i;:::-;;:::i;:::-;;;565:14:1;;558:22;540:41;;528:2;513:18;95176:284:0;;;;;;;;102251:118;;;;;;;;;;-1:-1:-1;102251:118:0;;;;;:::i;:::-;;:::i;:::-;;101233:136;;;;;;;;;;-1:-1:-1;101233:136:0;;;;;:::i;:::-;;:::i;99790:217::-;;;;;;;;;;-1:-1:-1;99790:217:0;;;;;:::i;:::-;;:::i;59436:100::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;61036:245::-;;;;;;;;;;-1:-1:-1;61036:245:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;3558:32:1;;;3540:51;;3528:2;3513:18;61036:245:0;3394:203:1;60599:371:0;;;;;;;;;;-1:-1:-1;60599:371:0;;;;;:::i;:::-;;:::i;94553:27::-;;;;;;;;;;-1:-1:-1;94553:27:0;;;;;;;;;;;;;;;:::i;55490:303::-;;;;;;;;;;;;;:::i;:::-;;;4547:25:1;;;4535:2;4520:18;55490:303:0;4401:177:1;62024:170:0;;;;;;;;;;-1:-1:-1;62024:170:0;;;;;:::i;:::-;;:::i;96148:179::-;;;;;;;;;;-1:-1:-1;96148:179:0;;;;;:::i;:::-;96259:7;96291:28;;;:19;:28;;;;;;;96148:179;101713:347;;;;;;;;;;-1:-1:-1;101713:347:0;;;;;:::i;:::-;;:::i;98694:561::-;;;;;;;;;;-1:-1:-1;98694:561:0;;;;;:::i;:::-;;:::i;100287:240::-;;;;;;;;;;-1:-1:-1;100287:240:0;;;;;:::i;:::-;;:::i;102377:145::-;;;;;;;;;;-1:-1:-1;102377:145:0;;;;;:::i;:::-;;:::i;92611:42::-;;;;;;;;;;;;92648:5;92611:42;;104219:209;;;;;;;;;;-1:-1:-1;104219:209:0;;;;;:::i;:::-;;:::i;62265:185::-;;;;;;;;;;-1:-1:-1;62265:185:0;;;;;:::i;:::-;;:::i;104006:205::-;;;;;;;;;;-1:-1:-1;104006:205:0;;;;;:::i;:::-;;:::i;94984:120::-;;;;;;;;;;-1:-1:-1;94984:120:0;;;;;:::i;:::-;;:::i;4234:149::-;;;;;;;;;;;;;:::i;103840:158::-;;;;;;;;;;-1:-1:-1;103840:158:0;;;;;:::i;:::-;;:::i;2358:146::-;;;;;;;;;;-1:-1:-1;2358:146:0;;;;;:::i;:::-;2479:17;;-1:-1:-1;;;;;2466:30:0;;;2479:17;;2466:30;;2358:146;95795:166;;;;;;;;;;-1:-1:-1;95795:166:0;;;;;:::i;:::-;95899:7;95931:22;;;:13;:22;;;;;;-1:-1:-1;;;;;95931:22:0;;95795:166;75890:86;;;;;;;;;;-1:-1:-1;75961:7:0;;-1:-1:-1;;;75961:7:0;;;;75890:86;;96940:208;;;;;;;;;;;;;:::i;59244:125::-;;;;;;;;;;-1:-1:-1;59244:125:0;;;;;:::i;:::-;;:::i;102730:201::-;;;;;;;;;;-1:-1:-1;102730:201:0;;;;;:::i;:::-;;:::i;56660:206::-;;;;;;;;;;-1:-1:-1;56660:206:0;;;;;:::i;:::-;;:::i;100605:444::-;;;;;;;;;;-1:-1:-1;100605:444:0;;;;;:::i;:::-;;:::i;78789:103::-;;;;;;;;;;;;;:::i;96736:196::-;;;;;;;;;;-1:-1:-1;96736:196:0;;;;;:::i;:::-;;:::i;99394:257::-;;;;;;:::i;:::-;;:::i;101558:147::-;;;;;;;;;;-1:-1:-1;101558:147:0;;;;;:::i;:::-;;:::i;92660:50::-;;;;;;;;;;;;92700:10;92660:50;;2126:108;;;;;;;;;;-1:-1:-1;2209:17:0;;-1:-1:-1;;;;;2209:17:0;2126:108;;96335:194;;;;;;;;;;-1:-1:-1;96335:194:0;;;;;:::i;:::-;-1:-1:-1;;;;;96481:40:0;96449:7;96481:40;;;:31;:40;;;;;;;96335:194;78138:87;;;;;;;;;;-1:-1:-1;78211:6:0;;-1:-1:-1;;;;;78211:6:0;78138:87;;59605:104;;;;;;;;;;;;;:::i;97950:736::-;;;;;;:::i;:::-;;:::i;97318:593::-;;;;;;:::i;:::-;;:::i;61353:319::-;;;;;;;;;;-1:-1:-1;61353:319:0;;;;;:::i;:::-;;:::i;96537:191::-;;;;;;;;;;-1:-1:-1;96537:191:0;;;;;:::i;:::-;96654:7;96686:34;;;:25;:34;;;;;;;96537:191;102988:182;;;;;;;;;;-1:-1:-1;102988:182:0;;;;;:::i;:::-;;:::i;62521:406::-;;;;;;;;;;-1:-1:-1;62521:406:0;;;;;:::i;:::-;;:::i;59780:415::-;;;;;;;;;;-1:-1:-1;59780:415:0;;;;;:::i;:::-;;:::i;100015:264::-;;;;;;;;;;-1:-1:-1;100015:264:0;;;;;:::i;:::-;;:::i;103423:235::-;;;;;;;;;;-1:-1:-1;103423:235:0;;;;;:::i;:::-;;:::i;102530:124::-;;;;;;;;;;-1:-1:-1;102530:124:0;;;;;:::i;:::-;;:::i;95534:253::-;;;;;;;;;;-1:-1:-1;95534:253:0;;;;;:::i;:::-;;:::i;61743:214::-;;;;;;;;;;-1:-1:-1;61743:214:0;;;;;:::i;:::-;-1:-1:-1;;;;;61914:25:0;;;61885:4;61914:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;61743:214;79047:201;;;;;;;;;;-1:-1:-1;79047:201:0;;;;;:::i;:::-;;:::i;102068:128::-;;;;;;;;;;-1:-1:-1;102068:128:0;;;;;:::i;:::-;;:::i;95969:171::-;;;;;;;;;;-1:-1:-1;95969:171:0;;;;;:::i;:::-;96076:7;96108:24;;;:15;:24;;;;;;;95969:171;95176:284;95307:4;-1:-1:-1;;;;;;95349:50:0;;-1:-1:-1;;;95349:50:0;;:103;;;95416:36;95440:11;95416:23;:36::i;:::-;95329:123;95176:284;-1:-1:-1;;95176:284:0:o;102251:118::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;;;;;;;;;102316:14;;::::1;::::0;:8:::1;::::0;:14:::1;::::0;::::1;::::0;::::1;:::i;:::-;;102357:3;102346:15;;;;;;:::i;:::-;;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;102251:118:::0;:::o;101233:136::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;101305:7:::1;:16:::0;;-1:-1:-1;;;;;;101305:16:0::1;;-1:-1:-1::0;;;;;101305:16:0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;101337:24:::1;::::0;::::1;::::0;-1:-1:-1;;101337:24:0::1;101233:136:::0;:::o;99790:217::-;75961:7;;-1:-1:-1;;;75961:7:0;;;;76215:9;76207:38;;;;-1:-1:-1;;;76207:38:0;;;;;;;:::i;:::-;99941:7:::1;115416:41;115435:12;:10;:12::i;:::-;115449:7;115416:18;:41::i;:::-;115408:63;;;::::0;-1:-1:-1;;;115408:63:0;;10375:2:1;115408:63:0::1;::::0;::::1;10357:21:1::0;10414:1;10394:18;;;10387:29;-1:-1:-1;;;10432:18:1;;;10425:39;10481:18;;115408:63:0::1;10173:332:1::0;115408:63:0::1;99966:33:::2;99980:7;99989:9;99966:13;:33::i;:::-;76256:1:::1;99790:217:::0;;:::o;59436:100::-;59490:13;59523:5;59516:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59436:100;:::o;61036:245::-;61140:7;61170:16;61178:7;61170;:16::i;:::-;61165:64;;61195:34;;-1:-1:-1;;;61195:34:0;;;;;;;;;;;61165:64;-1:-1:-1;61249:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;61249:24:0;;61036:245::o;60599:371::-;60672:13;60688:24;60704:7;60688:15;:24::i;:::-;60672:40;;60733:5;-1:-1:-1;;;;;60727:11:0;:2;-1:-1:-1;;;;;60727:11:0;;60723:48;;60747:24;;-1:-1:-1;;;60747:24:0;;;;;;;;;;;60723:48;60804:5;-1:-1:-1;;;;;60788:21:0;:12;:10;:12::i;:::-;-1:-1:-1;;;;;60788:21:0;;;:63;;;;;60814:37;60831:5;60838:12;:10;:12::i;60814:37::-;60813:38;60788:63;60784:138;;;60875:35;;-1:-1:-1;;;60875:35:0;;;;;;;;;;;60784:138;60934:28;60943:2;60947:7;60956:5;60934:8;:28::i;55490:303::-;55347:1;55744:12;55534:7;55728:13;:28;-1:-1:-1;;55728:46:0;;55490:303::o;62024:170::-;62158:28;62168:4;62174:2;62178:7;62158:9;:28::i;101713:347::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;101786:11:::1;:24:::0;;-1:-1:-1;;;;;;101786:24:0::1;-1:-1:-1::0;;;;;101786:24:0;;::::1;::::0;;::::1;::::0;;;101950:17:::1;::::0;101901:110:::1;::::0;-1:-1:-1;;;101901:110:0;;101950:17;::::1;101901:110;::::0;::::1;11069:51:1::0;-1:-1:-1;;11136:18:1;;;11129:34;101786:24:0;101901:26:::1;::::0;11042:18:1;;101901:110:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;102027:25:0::1;::::0;-1:-1:-1;;;;;102027:25:0;::::1;::::0;::::1;::::0;;;::::1;101713:347:::0;:::o;98694:561::-;75961:7;;99053:4;;-1:-1:-1;;;75961:7:0;;;;76215:9;76207:38;;;;-1:-1:-1;;;76207:38:0;;;;;;;:::i;:::-;98922:16:::1;::::0;113336:9:::1;::::0;::::1;;:23;::::0;::::1;;;;;;:::i;:::-;;;113328:50;;;;-1:-1:-1::0;;;113328:50:0::1;;;;;;;:::i;:::-;92648:5:::2;113456:13;:11;:13::i;:::-;:27;;113448:52;;;;-1:-1:-1::0;;;113448:52:0::2;;;;;;;:::i;:::-;98990:10:::3;99002:13;99017:5;99024:9;;114799:13;114785:10;:27;;114777:50;;;::::0;-1:-1:-1;;;114777:50:0;;12310:2:1;114777:50:0::3;::::0;::::3;12292:21:1::0;12349:2;12329:18;;;12322:30;-1:-1:-1;;;12368:18:1;;;12361:40;12418:18;;114777:50:0::3;12108:334:1::0;114777:50:0::3;114855:11;;114846:5;:20;114838:42;;;::::0;-1:-1:-1;;;114838:42:0;;12649:2:1;114838:42:0::3;::::0;::::3;12631:21:1::0;12688:1;12668:18;;;12661:29;-1:-1:-1;;;12706:18:1;;;12699:39;12755:18;;114838:42:0::3;12447:332:1::0;114838:42:0::3;114957:7;::::0;93527:42:::3;::::0;114913:25:::3;::::0;114957:7:::3;::::0;::::3;-1:-1:-1::0;;;;;114957:7:0::3;114983:12;:10;:12::i;:::-;115014:13;115046:5;115070:9;;114913:181;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;114891:244;;;::::0;-1:-1:-1;;;114891:244:0;;13725:2:1;114891:244:0::3;::::0;::::3;13707:21:1::0;13764:2;13744:18;;;13737:30;-1:-1:-1;;;13783:18:1;;;13776:43;13836:18;;114891:244:0::3;13523:337:1::0;114891:244:0::3;115214:13;115200:10;115168:15;:29;115184:12;:10;:12::i;:::-;-1:-1:-1::0;;;;;115168:29:0::3;-1:-1:-1::0;;;;;115168:29:0::3;;;;;;;;;;;;;:42;;;;:::i;:::-;:59;;115146:118;;;::::0;-1:-1:-1;;;115146:118:0;;14332:2:1;115146:118:0::3;::::0;::::3;14314:21:1::0;14371:1;14351:18;;;14344:29;-1:-1:-1;;;14389:18:1;;;14382:39;14438:18;;115146:118:0::3;14130:332:1::0;115146:118:0::3;115308:10;115275:15;:29;115291:12;:10;:12::i;:::-;-1:-1:-1::0;;;;;115275:29:0::3;-1:-1:-1::0;;;;;115275:29:0::3;;;;;;;;;;;;;:43;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;99188:37:0::4;::::0;-1:-1:-1;99200:10:0;99212:12:::4;:10;:12::i;:::-;99188:11;:37::i;:::-;-1:-1:-1::0;99243:4:0::4;::::0;98694:561;-1:-1:-1;;;;;;;;;;;;98694:561:0:o;100287:240::-;75961:7;;-1:-1:-1;;;75961:7:0;;;;76215:9;76207:38;;;;-1:-1:-1;;;76207:38:0;;;;;;;:::i;:::-;100444:7:::1;115587:12;:10;:12::i;:::-;115561:22;::::0;;;:13:::1;:22;::::0;;;;;-1:-1:-1;;;;;115561:22:0;;::::1;:38:::0;::::1;;115553:60;;;::::0;-1:-1:-1;;;115553:60:0;;14669:2:1;115553:60:0::1;::::0;::::1;14651:21:1::0;14708:1;14688:18;;;14681:29;-1:-1:-1;;;14726:18:1;;;14719:39;14775:18;;115553:60:0::1;14467:332:1::0;115553:60:0::1;-1:-1:-1::0;100469:39:0::2;::::0;;;:30:::2;:39;::::0;;;;;:50;;-1:-1:-1;;;;;;100469:50:0::2;-1:-1:-1::0;;;;;100469:50:0;;::::2;::::0;;;::::2;::::0;;100287:240::o;102377:145::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;102452:9:::1;:22:::0;;102464:10;;102452:9;-1:-1:-1;;102452:22:0::1;::::0;102464:10;102452:22:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;102503:10;102490:24;;;;;;;;:::i;:::-;;::::0;::::1;::::0;;;::::1;102377:145:::0;:::o;104219:209::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;104372:48:::1;104388:8;104398:12;104412:7;104372:15;:48::i;62265:185::-:0;62403:39;62420:4;62426:2;62430:7;62403:39;;;;;;;;;;;;:16;:39::i;104006:205::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;104157:46:::1;104172:8;104182:12;104196:6;104157:14;:46::i;94984:120::-:0;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;95063:25:::1;:33:::0;;-1:-1:-1;;95063:33:0::1;::::0;::::1;;::::0;;;::::1;::::0;;94984:120::o;4234:149::-;4294:13;4320:55;;;;;;;;;;;;;;;;;;;4234:149;:::o;103840:158::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;103958:32:::1;103973:8;103983:6;103958:14;:32::i;:::-;103840:158:::0;;:::o;96940:208::-;97072:7;39508:1;40106:7;;:19;40098:63;;;;-1:-1:-1;;;40098:63:0;;;;;;;:::i;:::-;39508:1;40239:7;:18;75961:7;;-1:-1:-1;;;75961:7:0;;;;76215:9:::1;76207:38;;;;-1:-1:-1::0;;;76207:38:0::1;;;;;;;:::i;:::-;97104:36:::2;97127:12;:10;:12::i;:::-;97104:22;:36::i;:::-;97097:43;;39464:1:::0;40418:7;:22;96940:208;:::o;59244:125::-;59308:7;59335:21;59348:7;59335:12;:21::i;:::-;:26;;59244:125;-1:-1:-1;;59244:125:0:o;102730:201::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;102815:17:::1;:55:::0;;-1:-1:-1;;;;;;102815:55:0::1;-1:-1:-1::0;;;;;102815:55:0;::::1;::::0;;::::1;::::0;;;102886:37:::1;::::0;::::1;::::0;-1:-1:-1;;102886:37:0::1;102730:201:::0;:::o;56660:206::-;56724:7;-1:-1:-1;;;;;56748:19:0;;56744:60;;56776:28;;-1:-1:-1;;;56776:28:0;;;;;;;;;;;56744:60;-1:-1:-1;;;;;;56830:19:0;;;;;:12;:19;;;;;:27;;;;56660:206::o;100605:444::-;100702:22;;-1:-1:-1;;;100702:22:0;;;;;4547:25:1;;;100686:13:0;;100702:4;;:12;;4520:18:1;;100702:22:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100686:38;;100773:5;-1:-1:-1;;;;;100757:21:0;:12;:10;:12::i;:::-;-1:-1:-1;;;;;100757:21:0;;:79;;;;100815:21;100827:8;100815:11;:21::i;:::-;-1:-1:-1;;;;;100799:37:0;:12;:10;:12::i;:::-;-1:-1:-1;;;;;100799:37:0;;100757:79;:137;;;;100857:37;100874:5;100881:12;:10;:12::i;100857:37::-;100735:252;;;;-1:-1:-1;;;100735:252:0;;15622:2:1;100735:252:0;;;15604:21:1;15661:2;15641:18;;;15634:30;15700:34;15680:18;;;15673:62;15771:34;15751:18;;;15744:62;-1:-1:-1;;;15822:19:1;;;15815:32;15864:19;;100735:252:0;15420:469:1;100735:252:0;100998:43;101014:5;101021:9;101032:8;100998:15;:43::i;78789:103::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;78854:30:::1;78881:1;78854:18;:30::i;:::-;78789:103::o:0;96736:196::-;96858:7;96890:34;96916:7;96890:25;:34::i;99394:257::-;99567:4;39508:1;40106:7;;:19;40098:63;;;;-1:-1:-1;;;40098:63:0;;;;;;;:::i;:::-;39508:1;40239:7;:18;75961:7;;-1:-1:-1;;;75961:7:0;;;;76215:9:::1;76207:38;;;;-1:-1:-1::0;;;76207:38:0::1;;;;;;;:::i;:::-;99589:32:::2;99603:7;99612:8;99589:13;:32::i;:::-;;;;;;;;99639:4;99632:11;;39464:1:::0;40418:7;:22;99394:257;;-1:-1:-1;;99394:257:0:o;101558:147::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;101644:11:::1;:24:::0;;;;101679:8:::1;:18:::0;101558:147::o;59605:104::-;59661:13;59694:7;59687:14;;;;;:::i;97950:736::-;98398:4;39508:1;40106:7;;:19;40098:63;;;;-1:-1:-1;;;40098:63:0;;;;;;;:::i;:::-;39508:1;40239:7;:18;75961:7;;-1:-1:-1;;;75961:7:0;;;;76215:9:::1;76207:38;;;;-1:-1:-1::0;;;76207:38:0::1;;;;;;;:::i;:::-;98222:20:::2;::::0;113336:9:::2;::::0;::::2;;:23;::::0;::::2;;;;;;:::i;:::-;;;113328:50;;;;-1:-1:-1::0;;;113328:50:0::2;;;;;;;:::i;:::-;92648:5:::3;113456:13;:11;:13::i;:::-;:27;;113448:52;;;;-1:-1:-1::0;;;113448:52:0::3;;;;;;;:::i;:::-;98297:10:::4;113579:17;113608:10;;113599:6;:19;;;;:::i;:::-;113579:39;;113650:9;113637;:22;;113629:42;;;::::0;-1:-1:-1;;;113629:42:0;;16269:2:1;113629:42:0::4;::::0;::::4;16251:21:1::0;16308:1;16288:18;;;16281:29;-1:-1:-1;;;16326:18:1;;;16319:37;16373:18;;113629:42:0::4;16067:330:1::0;113629:42:0::4;98335:10:::5;98347:13;98362:5;98369:9;;113885:13;113871:10;:27;;113863:50;;;::::0;-1:-1:-1;;;113863:50:0;;12310:2:1;113863:50:0::5;::::0;::::5;12292:21:1::0;12349:2;12329:18;;;12322:30;-1:-1:-1;;;12368:18:1;;;12361:40;12418:18;;113863:50:0::5;12108:334:1::0;113863:50:0::5;113941:8;;113932:5;:17;113924:39;;;::::0;-1:-1:-1;;;113924:39:0;;12649:2:1;113924:39:0::5;::::0;::::5;12631:21:1::0;12688:1;12668:18;;;12661:29;-1:-1:-1;;;12706:18:1;;;12699:39;12755:18;;113924:39:0::5;12447:332:1::0;113924:39:0::5;114040:7;::::0;93527:42:::5;::::0;113996:25:::5;::::0;114040:7:::5;::::0;::::5;-1:-1:-1::0;;;;;114040:7:0::5;114066:12;:10;:12::i;:::-;114097:13;114129:5;114202:9;;113996:230;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;113974:293;;;::::0;-1:-1:-1;;;113974:293:0;;13725:2:1;113974:293:0::5;::::0;::::5;13707:21:1::0;13764:2;13744:18;;;13737:30;-1:-1:-1;;;13783:18:1;;;13776:43;13836:18;;113974:293:0::5;13523:337:1::0;113974:293:0::5;114373:13;114342:10;114300:25;:39;114326:12;:10;:12::i;:::-;-1:-1:-1::0;;;;;114300:39:0::5;-1:-1:-1::0;;;;;114300:39:0::5;;;;;;;;;;;;;:52;;;;:::i;:::-;:86;;114278:145;;;::::0;-1:-1:-1;;;114278:145:0;;14332:2:1;114278:145:0::5;::::0;::::5;14314:21:1::0;14371:1;14351:18;;;14344:29;-1:-1:-1;;;14389:18:1;;;14382:39;14438:18;;114278:145:0::5;14130:332:1::0;114278:145:0::5;114477:10;114434:25;:39;114460:12;:10;:12::i;:::-;-1:-1:-1::0;;;;;114434:39:0::5;-1:-1:-1::0;;;;;114434:39:0::5;;;;;;;;;;;;;:53;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;98552:19:0::6;::::0;-1:-1:-1;98574:37:0::6;98586:10:::0;98598:12:::6;:10;:12::i;98574:37::-;98552:59;;98622:34;98641:11;98654:1;98622:18;:34::i;:::-;-1:-1:-1::0;;98674:4:0::6;40418:7:::0;:22;;;98674:4;97950:736;-1:-1:-1;;;;;;;;;;;;;97950:736:0:o;97318:593::-;97568:4;39508:1;40106:7;;:19;40098:63;;;;-1:-1:-1;;;40098:63:0;;;;;;;:::i;:::-;39508:1;40239:7;:18;75961:7;;-1:-1:-1;;;75961:7:0;;;;76215:9:::1;76207:38;;;;-1:-1:-1::0;;;76207:38:0::1;;;;;;;:::i;:::-;97470:17:::2;::::0;113336:9:::2;::::0;::::2;;:23;::::0;::::2;;;;;;:::i;:::-;;;113328:50;;;;-1:-1:-1::0;;;113328:50:0::2;;;;;;;:::i;:::-;92648:5:::3;113456:13;:11;:13::i;:::-;:27;;113448:52;;;;-1:-1:-1::0;;;113448:52:0::3;;;;;;;:::i;:::-;97542:6:::4;113579:17;113608:10;;113599:6;:19;;;;:::i;:::-;113579:39;;113650:9;113637;:22;;113629:42;;;::::0;-1:-1:-1;;;113629:42:0;;16269:2:1;113629:42:0::4;::::0;::::4;16251:21:1::0;16308:1;16288:18;;;16281:29;-1:-1:-1;;;16326:18:1;;;16319:37;16373:18;;113629:42:0::4;16067:330:1::0;113629:42:0::4;97704:19:::5;97726:33;97738:6;97746:12;:10;:12::i;97726:33::-;97704:55;;97770:34;97789:11;97802:1;97770:18;:34::i;:::-;97899:4;97892:11;;;-1:-1:-1::0;;39464:1:0;40418:7;:22;-1:-1:-1;97318:593:0;;-1:-1:-1;97318:593:0:o;61353:319::-;61496:12;:10;:12::i;:::-;-1:-1:-1;;;;;61484:24:0;:8;-1:-1:-1;;;;;61484:24:0;;61480:54;;61517:17;;-1:-1:-1;;;61517:17:0;;;;;;;;;;;61480:54;61592:8;61547:18;:32;61566:12;:10;:12::i;:::-;-1:-1:-1;;;;;61547:32:0;;;;;;;;;;;;;;;;;-1:-1:-1;61547:32:0;;;:42;;;;;;;;;;;;:53;;-1:-1:-1;;61547:53:0;;;;;;;;;;;61631:12;:10;:12::i;:::-;-1:-1:-1;;;;;61616:48:0;;61655:8;61616:48;;;;565:14:1;558:22;540:41;;528:2;513:18;;400:187;61616:48:0;;;;;;;;61353:319;;:::o;102988:182::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;103068:13:::1;:46:::0;;-1:-1:-1;;;;;;103068:46:0::1;-1:-1:-1::0;;;;;103068:46:0;::::1;::::0;;::::1;::::0;;;103130:32:::1;::::0;::::1;::::0;-1:-1:-1;;103130:32:0::1;102988:182:::0;:::o;62521:406::-;62688:28;62698:4;62704:2;62708:7;62688:9;:28::i;:::-;-1:-1:-1;;;;;62745:13:0;;44107:19;:23;;62745:89;;;;;62778:56;62809:4;62815:2;62819:7;62828:5;62778:30;:56::i;:::-;62777:57;62745:89;62727:193;;;62868:40;;-1:-1:-1;;;62868:40:0;;;;;;;;;;;62727:193;62521:406;;;;:::o;59780:415::-;59898:13;59934:16;59942:7;59934;:16::i;:::-;59929:59;;59959:29;;-1:-1:-1;;;59959:29:0;;;;;;;;;;;59929:59;60001:21;60025:10;:8;:10::i;:::-;60001:34;;60072:7;60066:21;60091:1;60066:26;:121;;;;;;;;;;;;;;;;;60136:7;60145:18;:7;:16;:18::i;:::-;60119:45;;;;;;;;;:::i;:::-;;;;;;;;;;;;;60066:121;60046:141;59780:415;-1:-1:-1;;;59780:415:0:o;100015:264::-;75961:7;;-1:-1:-1;;;75961:7:0;;;;76215:9;76207:38;;;;-1:-1:-1;;;76207:38:0;;;;;;;:::i;:::-;100164:7:::1;115587:12;:10;:12::i;:::-;115561:22;::::0;;;:13:::1;:22;::::0;;;;;-1:-1:-1;;;;;115561:22:0;;::::1;:38:::0;::::1;;115553:60;;;::::0;-1:-1:-1;;;115553:60:0;;14669:2:1;115553:60:0::1;::::0;::::1;14651:21:1::0;14708:1;14688:18;;;14681:29;-1:-1:-1;;;14726:18:1;;;14719:39;14775:18;;115553:60:0::1;14467:332:1::0;115553:60:0::1;100207:7:::2;115416:41;115435:12;:10;:12::i;115416:41::-;115408:63;;;::::0;-1:-1:-1;;;115408:63:0;;10375:2:1;115408:63:0::2;::::0;::::2;10357:21:1::0;10414:1;10394:18;;;10387:29;-1:-1:-1;;;10432:18:1;;;10425:39;10481:18;;115408:63:0::2;10173:332:1::0;115408:63:0::2;100232:39:::3;100249:7;100258:12;100232:16;:39::i;103423:235::-:0;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;2312:17;:30;;-1:-1:-1;;;;;;2312:30:0;-1:-1:-1;;;;;2312:30:0;;;;;103423:235;:::o;103509:39::-:1;103423:235:::0;:::o;102530:124::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;102596:5:::1;:29;;102615:10;:8;:10::i;102596:29::-;102604:8;:6;:8::i;95534:253::-:0;95595:7;95637:17;95645:8;95637:7;:17::i;:::-;95615:121;;;;-1:-1:-1;;;95615:121:0;;17079:2:1;95615:121:0;;;17061:21:1;17118:2;17098:18;;;17091:30;17157:34;17137:18;;;17130:62;-1:-1:-1;;;17208:18:1;;;17201:52;17270:19;;95615:121:0;16877:418:1;95615:121:0;-1:-1:-1;95754:25:0;;;;:15;:25;;;;;;-1:-1:-1;;;;;95754:25:0;;95534:253::o;79047:201::-;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;79136:22:0;::::1;79128:73;;;::::0;-1:-1:-1;;;79128:73:0;;17502:2:1;79128:73:0::1;::::0;::::1;17484:21:1::0;17541:2;17521:18;;;17514:30;17580:34;17560:18;;;17553:62;-1:-1:-1;;;17631:18:1;;;17624:36;17677:19;;79128:73:0::1;17300:402:1::0;79128:73:0::1;79212:28;79231:8;79212:18;:28::i;102068:128::-:0;78369:12;:10;:12::i;:::-;-1:-1:-1;;;;;78358:23:0;:7;78211:6;;-1:-1:-1;;;;;78211:6:0;;78138:87;78358:7;-1:-1:-1;;;;;78358:23:0;;78350:68;;;;-1:-1:-1;;;78350:68:0;;;;;;;:::i;:::-;102135:10:::1;:18:::0;;;102169:19:::1;::::0;4547:25:1;;;102169:19:0::1;::::0;4535:2:1;4520:18;102169:19:0::1;;;;;;;102068:128:::0;:::o;2764:558::-;2826:11;2873:2;2854:8;:21;;;;:55;;-1:-1:-1;2479:17:0;;-1:-1:-1;;;;;2479:17:0;2898:10;2466:30;2879;2850:465;;;-1:-1:-1;;;3220:14:0;3216:22;3203:36;3200:2;3196:44;2764:558;:::o;2850:465::-;-1:-1:-1;3293:10:0;2764:558;:::o;56241:355::-;56388:4;-1:-1:-1;;;;;;56430:40:0;;-1:-1:-1;;;56430:40:0;;:105;;-1:-1:-1;;;;;;;56487:48:0;;-1:-1:-1;;;56487:48:0;56430:105;:158;;;-1:-1:-1;;;;;;;;;;25120:40:0;;;56552:36;25011:157;112158:190;112277:7;112309:31;:29;:31::i;:::-;112302:38;;112158:190;:::o;112664:445::-;112793:4;112837:16;112845:7;112837;:16::i;:::-;112815:110;;;;-1:-1:-1;;;112815:110:0;;17909:2:1;112815:110:0;;;17891:21:1;17948:2;17928:18;;;17921:30;17987:34;17967:18;;;17960:62;-1:-1:-1;;;18038:18:1;;;18031:42;18090:19;;112815:110:0;17707:408:1;112815:110:0;112936:13;112952:16;112960:7;112952;:16::i;:::-;112936:32;;112998:5;-1:-1:-1;;;;;112987:16:0;:7;-1:-1:-1;;;;;112987:16:0;;:65;;;-1:-1:-1;;;;;;61914:25:0;;;61885:4;61914:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;113020:32;112987:113;;;;113093:7;-1:-1:-1;;;;;113069:31:0;:20;113081:7;113069:11;:20::i;:::-;-1:-1:-1;;;;;113069:31:0;;112987:113;112979:122;112664:445;-1:-1:-1;;;;112664:445:0:o;106692:386::-;106771:24;;;;:15;:24;;;;;;;:36;;;106949:13;;:71;;-1:-1:-1;;;106949:71:0;;106988:4;106949:71;;;18316:51:1;18383:18;;;18376:34;;;107005:13:0;;;18426:18:1;;;18419:50;-1:-1:-1;;;;;106949:13:0;;;;:30;;18289:18:1;;106949:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107051:7;107038:32;107060:9;107038:32;;;;4547:25:1;;4535:2;4520:18;;4401:177;107038:32:0;;;;;;;;106692:386;;:::o;63182:213::-;63239:4;63295:7;55347:1;63276:26;;:66;;;;;63329:13;;63319:7;:23;63276:66;:111;;;;-1:-1:-1;;63360:20:0;;;;:11;:20;;;;;:27;-1:-1:-1;;;63360:27:0;;;;63359:28;;63182:213::o;71667:196::-;71782:24;;;;:15;:24;;;;;;:29;;-1:-1:-1;;;;;;71782:29:0;-1:-1:-1;;;;;71782:29:0;;;;;;;;;71827:28;;71782:24;;71827:28;;;;;;;71667:196;;;:::o;111617:320::-;111792:1;111765:24;;;:15;:24;;;;;;:28;;;111821:13;;:61;;-1:-1:-1;;;111821:61:0;;111860:4;111821:61;;;18316:51:1;18383:18;;;18376:34;;;18426:18;;;18419:50;;;;-1:-1:-1;;;;;111821:13:0;;:30;;18289:18:1;;111821:61:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;111895:34;111911:4;111917:2;111921:7;111895:15;:34::i;104676:1072::-;104766:19;104803:18;104824:13;:11;:13::i;:::-;104803:34;-1:-1:-1;92648:5:0;104912:19;104925:6;104803:34;104912:19;:::i;:::-;:32;104908:97;;;104970:23;104983:10;92648:5;104970:23;:::i;:::-;104961:32;;104908:97;105132:26;105142:7;105151:6;105132:9;:26::i;:::-;105192:10;;105183:19;;:6;:19;:::i;:::-;105169:33;-1:-1:-1;105262:19:0;105292:12;;;;:::i;:::-;;;;105320:9;105315:284;105335:6;105331:1;:10;105315:284;;;105449:7;105417:13;:29;105431:14;105444:1;105431:10;:14;:::i;:::-;105417:29;;;;;;;;;;;-1:-1:-1;105417:29:0;:39;;-1:-1:-1;;;;;;105417:39:0;-1:-1:-1;;;;;105417:39:0;;;;;;;;;;105486:31;105502:14;105515:1;105502:10;:14;:::i;:::-;105486:15;:31::i;:::-;105471:46;;;;:::i;:::-;;-1:-1:-1;105343:3:0;;;;:::i;:::-;;;;105315:284;;;;105688:52;105705:10;105688:52;;;;;;;;;;;;;-1:-1:-1;;;105688:52:0;;;105728:11;105688:16;:52::i;:::-;104792:956;;104676:1072;;;;:::o;89457:510::-;-1:-1:-1;;;;;89617:24:0;;89609:46;;;;-1:-1:-1;;;89609:46:0;;;;;;;:::i;:::-;89670:38;;-1:-1:-1;;;89670:38:0;;;;;4547:25:1;;;89720:4:0;;-1:-1:-1;;;;;89670:29:0;;;;;4520:18:1;;89670:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;89670:55:0;;89666:294;;89742:134;;-1:-1:-1;;;89742:134:0;;89803:4;89742:134;;;19335:34:1;-1:-1:-1;;;;;19405:15:1;;;19385:18;;;19378:43;19437:18;;;19430:34;;;89742::0;;;;;19270:18:1;;89742:134:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89940:7;89926:12;-1:-1:-1;;;;;89896:52:0;89916:8;-1:-1:-1;;;;;89896:52:0;;;;;;;;;;;89457:510;;;:::o;89026:423::-;-1:-1:-1;;;;;89184:24:0;;89176:46;;;;-1:-1:-1;;;89176:46:0;;;;;;;:::i;:::-;89237:45;;-1:-1:-1;;;89237:45:0;;89276:4;89237:45;;;3540:51:1;89286:6:0;;-1:-1:-1;;;;;89237:30:0;;;;;3513:18:1;;89237:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:55;89233:209;;89309:51;-1:-1:-1;;;;;89309:33:0;;89343:8;89353:6;89309:33;:51::i;:::-;89409:12;-1:-1:-1;;;;;89380:50:0;89399:8;-1:-1:-1;;;;;89380:50:0;;89423:6;89380:50;;;;4547:25:1;;4535:2;4520:18;;4401:177;89380:50:0;;;;;;;;89026:423;;;:::o;88691:327::-;-1:-1:-1;;;;;88816:24:0;;88808:46;;;;-1:-1:-1;;;88808:46:0;;;;;;;:::i;:::-;88894:6;88869:21;:31;88865:146;;88917:26;-1:-1:-1;;;;;88917:18:0;;88936:6;88917:18;:26::i;:::-;88982:8;-1:-1:-1;;;;;88963:36:0;;88992:6;88963:36;;;;4547:25:1;;4535:2;4520:18;;4401:177;110842:479:0;-1:-1:-1;;;;;110979:41:0;;110928:7;110979:41;;;:31;:41;;;;;;111039:19;111031:41;;;;-1:-1:-1;;;111031:41:0;;19866:2:1;111031:41:0;;;19848:21:1;19905:1;19885:18;;;19878:29;-1:-1:-1;;;19923:18:1;;;19916:39;19972:18;;111031:41:0;19664:332:1;111031:41:0;-1:-1:-1;;;;;111092:41:0;;;;;;:31;:41;;;;;111085:48;;;111144:47;;111092:41;111172:15;;111144:27;:47::i;:::-;111226:8;-1:-1:-1;;;;;111209:43:0;;111236:15;111209:43;;;;4547:25:1;;4535:2;4520:18;;4401:177;111209:43:0;;;;;;;;111298:15;110842:479;-1:-1:-1;;110842:479:0:o;58041:1141::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;58184:7:0;;55347:1;58233:23;;:47;;;;;58267:13;;58260:4;:20;58233:47;58229:886;;;58301:31;58335:17;;;:11;:17;;;;;;;;;58301:51;;;;;;;;;-1:-1:-1;;;;;58301:51:0;;;;-1:-1:-1;;;58301:51:0;;;;;;;;;;;-1:-1:-1;;;58301:51:0;;;;;;;;;;;;;;58371:729;;58421:14;;-1:-1:-1;;;;;58421:28:0;;58417:101;;58485:9;58041:1141;-1:-1:-1;;;58041:1141:0:o;58417:101::-;-1:-1:-1;;;58860:6:0;58905:17;;;;:11;:17;;;;;;;;;58893:29;;;;;;;;;-1:-1:-1;;;;;58893:29:0;;;;;-1:-1:-1;;;58893:29:0;;;;;;;;;;;-1:-1:-1;;;58893:29:0;;;;;;;;;;;;;58953:28;58949:109;;59021:9;58041:1141;-1:-1:-1;;;58041:1141:0:o;58949:109::-;58820:261;;;58282:833;58229:886;59143:31;;-1:-1:-1;;;59143:31:0;;;;;;;;;;;105850:237;105982:25;;;;:15;:25;;;;;;:37;;-1:-1:-1;;;;;;105982:37:0;-1:-1:-1;;;;;105982:37:0;;;;;;;;;106035:44;;105982:25;;106035:44;;;;;;;105850:237;;;:::o;79408:191::-;79501:6;;;-1:-1:-1;;;;;79518:17:0;;;-1:-1:-1;;;;;;79518:17:0;;;;;;;79551:40;;79501:6;;;79518:17;79501:6;;79551:40;;79482:16;;79551:40;79471:128;79408:191;:::o;107373:319::-;107475:7;107519:39;;;:30;:39;;;;;;-1:-1:-1;;;;;107519:39:0;;107569:90;;-1:-1:-1;;107625:22:0;;;;:13;:22;;;;;;-1:-1:-1;;;;;107625:22:0;;107373:319::o;108689:1930::-;108799:23;109133:25;;;:15;:25;;;;;;109076:4;;109102:8;;108799:23;;;;109177:13;109169:35;;;;-1:-1:-1;;;109169:35:0;;20203:2:1;109169:35:0;;;20185:21:1;20242:1;20222:18;;;20215:29;-1:-1:-1;;;20260:18:1;;;20253:39;20309:18;;109169:35:0;20001:332:1;109169:35:0;109236:9;109223;:22;;109215:44;;;;-1:-1:-1;;;109215:44:0;;20540:2:1;109215:44:0;;;20522:21:1;20579:1;20559:18;;;20552:29;-1:-1:-1;;;20597:18:1;;;20590:39;20646:18;;109215:44:0;20338:332:1;109215:44:0;109294:9;109352:17;109360:8;109352:7;:17::i;:::-;109341:28;;109391:12;:10;:12::i;:::-;109380:23;;109466:35;109492:8;109466:25;:35::i;:::-;109512:20;109535:35;;;:25;:35;;;;;;;;;109605:19;:29;;;;;;;109446:55;;-1:-1:-1;109535:35:0;109663:16;;;;;:37;;;109699:1;109683:13;:17;109663:37;:66;;;;;109716:13;109704:9;:25;109663:66;109645:279;;;92764:3;109820:12;109791:25;109803:13;109791:9;:25;:::i;:::-;109790:42;;;;:::i;:::-;109789:80;;;;:::i;:::-;109756:113;-1:-1:-1;109884:28:0;109756:113;109884:28;;:::i;:::-;;;109645:279;109934:29;;;;:19;:29;;;;;:41;;;110034:17;;110030:117;;-1:-1:-1;;;;;110068:50:0;;;;;;:31;:50;;;;;:67;;110122:13;;110068:50;:67;;110122:13;;110068:67;:::i;:::-;;;;-1:-1:-1;;110030:117:0;110186:39;110196:8;110206;110216;110186:9;:39::i;:::-;110243:177;;;21134:25:1;;;-1:-1:-1;;;;;21195:32:1;;;21190:2;21175:18;;21168:60;21244:18;;;21237:34;;;110243:177:0;;;;;;;110271:8;;110243:177;;21122:2:1;21107:18;110243:177:0;;;;;;;110466:15;;110462:99;;110498:51;-1:-1:-1;;;;;110498:27:0;;110526:11;110539:9;110498:27;:51::i;:::-;110571:40;110590:9;110601;110571:18;:40::i;:::-;109039:1580;;;108689:1930;;;;;;;;;;:::o;111329:280::-;111458:15;111476:21;111488:9;111476;:21;:::i;:::-;111458:39;-1:-1:-1;111512:11:0;;111508:94;;111540:50;111572:7;111581:8;111548:12;:10;:12::i;:::-;-1:-1:-1;;;;;111540:31:0;;:50;:31;:50::i;72355:772::-;72518:4;72568:2;-1:-1:-1;;;;;72552:36:0;;72607:12;:10;:12::i;:::-;72638:4;72661:7;72687:5;72552:155;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;72552:155:0;;;;;;;;-1:-1:-1;;72552:155:0;;;;;;;;;;;;:::i;:::-;;;72535:585;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;72878:6;:13;72895:1;72878:18;72874:235;;72924:40;;-1:-1:-1;;;72924:40:0;;;;;;;;;;;72874:235;73067:6;73061:13;73052:6;73048:2;73044:15;73037:38;72535:585;-1:-1:-1;;;;;;72763:55:0;-1:-1:-1;;;72763:55:0;;-1:-1:-1;72355:772:0;;;;;;:::o;104567:101::-;104619:13;104652:8;104645:15;;;;;:::i;40820:723::-;40876:13;41097:5;41106:1;41097:10;41093:53;;-1:-1:-1;;41124:10:0;;;;;;;;;;;;-1:-1:-1;;;41124:10:0;;;;;40820:723::o;41093:53::-;41171:5;41156:12;41212:78;41219:9;;41212:78;;41245:8;;;;:::i;:::-;;-1:-1:-1;41268:10:0;;-1:-1:-1;41276:2:0;41268:10;;:::i;:::-;;;41212:78;;;41300:19;41332:6;41322:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;41322:17:0;;41300:39;;41350:154;41357:10;;41350:154;;41384:11;41394:1;41384:11;;:::i;:::-;;-1:-1:-1;41453:10:0;41461:2;41453:5;:10;:::i;:::-;41440:24;;:2;:24;:::i;:::-;41427:39;;41410:6;41417;41410:14;;;;;;;;:::i;:::-;;;;:56;-1:-1:-1;;;;;41410:56:0;;;;;;;;-1:-1:-1;41481:11:0;41490:2;41481:11;;:::i;:::-;;;41350:154;;107086:279;92833:3;107179:12;:29;;107171:51;;;;-1:-1:-1;;;107171:51:0;;22481:2:1;107171:51:0;;;22463:21:1;22520:1;22500:18;;;22493:29;-1:-1:-1;;;22538:18:1;;;22531:39;22587:18;;107171:51:0;22279:332:1;107171:51:0;107250:34;;;;:25;:34;;;;;;;:49;;;107315:42;107276:7;;107315:42;;;;107287:12;4547:25:1;;4535:2;4520:18;;4401:177;76949:120:0;75961:7;;-1:-1:-1;;;75961:7:0;;;;76485:41;;;;-1:-1:-1;;;76485:41:0;;22818:2:1;76485:41:0;;;22800:21:1;22857:2;22837:18;;;22830:30;-1:-1:-1;;;22876:18:1;;;22869:50;22936:18;;76485:41:0;22616:344:1;76485:41:0;77008:7:::1;:15:::0;;-1:-1:-1;;;;77008:15:0::1;::::0;;77039:22:::1;77048:12;:10;:12::i;:::-;77039:22;::::0;-1:-1:-1;;;;;3558:32:1;;;3540:51;;3528:2;3513:18;77039:22:0::1;;;;;;;76949:120::o:0;76690:118::-;75961:7;;-1:-1:-1;;;75961:7:0;;;;76215:9;76207:38;;;;-1:-1:-1;;;76207:38:0;;;;;;;:::i;:::-;76750:7:::1;:14:::0;;-1:-1:-1;;;;76750:14:0::1;-1:-1:-1::0;;;76750:14:0::1;::::0;;76780:20:::1;76787:12;:10;:12::i;66512:2228::-:0;66725:35;66763:21;66776:7;66763:12;:21::i;:::-;66725:59;;66823:4;-1:-1:-1;;;;;66801:26:0;:13;:18;;;-1:-1:-1;;;;;66801:26:0;;66797:67;;66836:28;;-1:-1:-1;;;66836:28:0;;;;;;;;;;;66797:67;66877:22;66919:4;-1:-1:-1;;;;;66903:20:0;:12;:10;:12::i;:::-;-1:-1:-1;;;;;66903:20:0;;:73;;;;66940:36;66957:4;66963:12;:10;:12::i;66940:36::-;66903:126;;;;67017:12;:10;:12::i;:::-;-1:-1:-1;;;;;66993:36:0;:20;67005:7;66993:11;:20::i;:::-;-1:-1:-1;;;;;66993:36:0;;66903:126;66877:153;;67048:17;67043:66;;67074:35;;-1:-1:-1;;;67074:35:0;;;;;;;;;;;67043:66;-1:-1:-1;;;;;67124:16:0;;67120:52;;67149:23;;-1:-1:-1;;;67149:23:0;;;;;;;;;;;67120:52;67185:43;67207:4;67213:2;67217:7;67226:1;67185:21;:43::i;:::-;67293:35;67310:1;67314:7;67323:4;67293:8;:35::i;:::-;-1:-1:-1;;;;;67624:18:0;;;;;;;:12;:18;;;;;;;;:31;;-1:-1:-1;;67624:31:0;;;;;;;-1:-1:-1;;67624:31:0;;;;;;;67670:16;;;;;;;;;:29;;;;;;;;-1:-1:-1;67670:29:0;;;;;;;;;;;67750:20;;;:11;:20;;;;;;67785:18;;-1:-1:-1;;;;;;67818:49:0;;;;-1:-1:-1;;;67851:15:0;67818:49;;;;;;;;;;68141:11;;68201:24;;;;;68244:13;;67750:20;;68201:24;;68244:13;68240:384;;68454:13;;68439:11;:28;68435:174;;68492:20;;68561:28;;;;68535:54;;-1:-1:-1;;;68535:54:0;-1:-1:-1;;;;;;68535:54:0;;;-1:-1:-1;;;;;68492:20:0;;68535:54;;;;68435:174;67599:1036;;;68671:7;68667:2;-1:-1:-1;;;;;68652:27:0;68661:4;-1:-1:-1;;;;;68652:27:0;;;;;;;;;;;68690:42;66625:2115;;66512:2228;;;:::o;63403:104::-;63472:27;63482:2;63486:8;63472:27;;;;;;;;;;;;:9;:27::i;107798:489::-;107863:7;92648:5;107887:7;:21;107883:366;;-1:-1:-1;107932:13:0;;107798:489;-1:-1:-1;107798:489:0:o;107883:366::-;107977:4;107967:7;:14;107963:286;;;-1:-1:-1;108005:13:0;;107798:489;-1:-1:-1;107798:489:0:o;107963:286::-;108050:4;108040:7;:14;108036:213;;;-1:-1:-1;108078:13:0;;107798:489;-1:-1:-1;107798:489:0:o;108036:213::-;108123:4;108113:7;:14;108109:140;;;-1:-1:-1;108151:13:0;;107798:489;-1:-1:-1;107798:489:0:o;108109:140::-;108196:4;108186:7;:14;108182:67;;;-1:-1:-1;108224:13:0;;107798:489;-1:-1:-1;107798:489:0:o;108182:67::-;-1:-1:-1;108266:13:0;;107798:489;-1:-1:-1;107798:489:0:o;108295:386::-;108484:17;;108605:11;;108484:189;;-1:-1:-1;;;108484:189:0;;108468:4;;-1:-1:-1;;;;;108484:17:0;;;;:34;;:189;;108468:4;;108553:7;;108575:15;;108605:11;;;;108631;;108468:4;;108484:189;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;83182:211::-;83326:58;;;-1:-1:-1;;;;;11087:32:1;;83326:58:0;;;11069:51:1;11136:18;;;;11129:34;;;83326:58:0;;;;;;;;;;11042:18:1;;;;83326:58:0;;;;;;;;-1:-1:-1;;;;;83326:58:0;-1:-1:-1;;;83326:58:0;;;83299:86;;83319:5;;83299:19;:86::i;45073:317::-;45188:6;45163:21;:31;;45155:73;;;;-1:-1:-1;;;45155:73:0;;23816:2:1;45155:73:0;;;23798:21:1;23855:2;23835:18;;;23828:30;23894:31;23874:18;;;23867:59;23943:18;;45155:73:0;23614:353:1;45155:73:0;45242:12;45260:9;-1:-1:-1;;;;;45260:14:0;45282:6;45260:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45241:52;;;45312:7;45304:78;;;;-1:-1:-1;;;45304:78:0;;24384:2:1;45304:78:0;;;24366:21:1;24423:2;24403:18;;;24396:30;24462:34;24442:18;;;24435:62;24533:28;24513:18;;;24506:56;24579:19;;45304:78:0;24182:422:1;7955:619:0;8136:6;8111:21;:31;;8089:112;;;;-1:-1:-1;;;8089:112:0;;24811:2:1;8089:112:0;;;24793:21:1;24850:2;24830:18;;;24823:30;24889:33;24869:18;;;24862:61;24940:18;;8089:112:0;24609:355:1;8089:112:0;8293:12;8323:1;8312:8;:12;8311:127;;8405:33;;-1:-1:-1;;;;;8405:14:0;;;8427:6;;8405:33;;;;8427:6;8405:14;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8311:127;;;8341:48;;-1:-1:-1;;;;;8341:14:0;;;8376:8;;8363:6;;8341:48;;;;8363:6;8341:14;8376:8;8341:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8311:127;8292:146;;;8471:7;8449:117;;;;-1:-1:-1;;;8449:117:0;;25171:2:1;8449:117:0;;;25153:21:1;25210:2;25190:18;;;25183:30;25249:34;25229:18;;;25222:62;25320:30;25300:18;;;25293:58;25368:19;;8449:117:0;24969:424:1;106095:589:0;-1:-1:-1;;;;;106289:19:0;;106285:58;106325:7;106285:58;75961:7;;-1:-1:-1;;;75961:7:0;;;;106439:9;106431:65;;;;-1:-1:-1;;;106431:65:0;;25600:2:1;106431:65:0;;;25582:21:1;25639:2;25619:18;;;25612:30;25678:34;25658:18;;;25651:62;-1:-1:-1;;;25729:18:1;;;25722:41;25780:19;;106431:65:0;25398:407:1;106431:65:0;106513:25;;;;106509:168;;;106616:49;106632:5;106647:1;106651:13;106616:15;:49::i;63870:163::-;63993:32;63999:2;64003:8;64013:5;64020:4;63993:5;:32::i;85755:716::-;86179:23;86205:69;86233:4;86205:69;;;;;;;;;;;;;;;;;86213:5;-1:-1:-1;;;;;86205:27:0;;;:69;;;;;:::i;:::-;86289:17;;86179:95;;-1:-1:-1;86289:21:0;86285:179;;86386:10;86375:30;;;;;;;;;;;;:::i;:::-;86367:85;;;;-1:-1:-1;;;86367:85:0;;26012:2:1;86367:85:0;;;25994:21:1;26051:2;26031:18;;;26024:30;26090:34;26070:18;;;26063:62;-1:-1:-1;;;26141:18:1;;;26134:40;26191:19;;86367:85:0;25810:406:1;64292:1966:0;64431:20;64454:13;-1:-1:-1;;;;;64482:16:0;;64478:48;;64507:19;;-1:-1:-1;;;64507:19:0;;;;;;;;;;;64478:48;64541:8;64553:1;64541:13;64537:44;;64563:18;;-1:-1:-1;;;64563:18:0;;;;;;;;;;;64537:44;64594:61;64624:1;64628:2;64632:12;64646:8;64594:21;:61::i;:::-;-1:-1:-1;;;;;64932:16:0;;;;;;:12;:16;;;;;;;;:44;;-1:-1:-1;;64991:49:0;;64932:44;;;;;;;;64991:49;;;;-1:-1:-1;;64932:44:0;;;;;;64991:49;;;;;;;;;;;;;;;;65057:25;;;:11;:25;;;;;;:35;;-1:-1:-1;;;;;;65107:66:0;;;;-1:-1:-1;;;65157:15:0;65107:66;;;;;;;;;;65057:25;65254:23;;;65298:4;:23;;;;-1:-1:-1;;;;;;65306:13:0;;44107:19;:23;;65306:15;65294:832;;;65342:505;65373:38;;65398:12;;-1:-1:-1;;;;;65373:38:0;;;65390:1;;65373:38;;65390:1;;65373:38;65465:212;65534:1;65567:2;65600:14;;;;;;65645:5;65465:30;:212::i;:::-;65434:365;;65735:40;;-1:-1:-1;;;65735:40:0;;;;;;;;;;;65434:365;65842:3;65826:12;:19;65342:505;;65928:12;65911:13;;:29;65907:43;;65942:8;;;65907:43;65294:832;;;65991:120;66022:40;;66047:14;;;;;-1:-1:-1;;;;;66022:40:0;;;66039:1;;66022:40;;66039:1;;66022:40;66106:3;66090:12;:19;65991:120;;65294:832;-1:-1:-1;66140:13:0;:28;66190:60;62521:406;46557:229;46694:12;46726:52;46748:6;46756:4;46762:1;46765:12;46694;-1:-1:-1;;;;;44107:19:0;;;47964:60;;;;-1:-1:-1;;;47964:60:0;;26830:2:1;47964:60:0;;;26812:21:1;26869:2;26849:18;;;26842:30;26908:31;26888:18;;;26881:59;26957:18;;47964:60:0;26628:353:1;47964:60:0;48038:12;48052:23;48079:6;-1:-1:-1;;;;;48079:11:0;48098:5;48105:4;48079:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48037:73;;;;48128:51;48145:7;48154:10;48166:12;48128:16;:51::i;:::-;48121:58;47677:510;-1:-1:-1;;;;;;;47677:510:0:o;50363:712::-;50513:12;50542:7;50538:530;;;-1:-1:-1;50573:10:0;50566:17;;50538:530;50687:17;;:21;50683:374;;50885:10;50879:17;50946:15;50933:10;50929:2;50925:19;50918:44;50683:374;51028:12;51021:20;;-1:-1:-1;;;51021:20:0;;;;;;;;:::i;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:131:1;-1:-1:-1;;;;;;88:32:1;;78:43;;68:71;;135:1;132;125:12;150:245;208:6;261:2;249:9;240:7;236:23;232:32;229:52;;;277:1;274;267:12;229:52;316:9;303:23;335:30;359:5;335:30;:::i;592:127::-;653:10;648:3;644:20;641:1;634:31;684:4;681:1;674:15;708:4;705:1;698:15;724:632;789:5;819:18;860:2;852:6;849:14;846:40;;;866:18;;:::i;:::-;941:2;935:9;909:2;995:15;;-1:-1:-1;;991:24:1;;;1017:2;987:33;983:42;971:55;;;1041:18;;;1061:22;;;1038:46;1035:72;;;1087:18;;:::i;:::-;1127:10;1123:2;1116:22;1156:6;1147:15;;1186:6;1178;1171:22;1226:3;1217:6;1212:3;1208:16;1205:25;1202:45;;;1243:1;1240;1233:12;1202:45;1293:6;1288:3;1281:4;1273:6;1269:17;1256:44;1348:1;1341:4;1332:6;1324;1320:19;1316:30;1309:41;;;;724:632;;;;;:::o;1361:451::-;1430:6;1483:2;1471:9;1462:7;1458:23;1454:32;1451:52;;;1499:1;1496;1489:12;1451:52;1539:9;1526:23;1572:18;1564:6;1561:30;1558:50;;;1604:1;1601;1594:12;1558:50;1627:22;;1680:4;1672:13;;1668:27;-1:-1:-1;1658:55:1;;1709:1;1706;1699:12;1658:55;1732:74;1798:7;1793:2;1780:16;1775:2;1771;1767:11;1732:74;:::i;1817:131::-;-1:-1:-1;;;;;1892:31:1;;1882:42;;1872:70;;1938:1;1935;1928:12;1953:247;2012:6;2065:2;2053:9;2044:7;2040:23;2036:32;2033:52;;;2081:1;2078;2071:12;2033:52;2120:9;2107:23;2139:31;2164:5;2139:31;:::i;2205:248::-;2273:6;2281;2334:2;2322:9;2313:7;2309:23;2305:32;2302:52;;;2350:1;2347;2340:12;2302:52;-1:-1:-1;;2373:23:1;;;2443:2;2428:18;;;2415:32;;-1:-1:-1;2205:248:1:o;2458:258::-;2530:1;2540:113;2554:6;2551:1;2548:13;2540:113;;;2630:11;;;2624:18;2611:11;;;2604:39;2576:2;2569:10;2540:113;;;2671:6;2668:1;2665:13;2662:48;;;-1:-1:-1;;2706:1:1;2688:16;;2681:27;2458:258::o;2721:::-;2763:3;2801:5;2795:12;2828:6;2823:3;2816:19;2844:63;2900:6;2893:4;2888:3;2884:14;2877:4;2870:5;2866:16;2844:63;:::i;:::-;2961:2;2940:15;-1:-1:-1;;2936:29:1;2927:39;;;;2968:4;2923:50;;2721:258;-1:-1:-1;;2721:258:1:o;2984:220::-;3133:2;3122:9;3115:21;3096:4;3153:45;3194:2;3183:9;3179:18;3171:6;3153:45;:::i;3209:180::-;3268:6;3321:2;3309:9;3300:7;3296:23;3292:32;3289:52;;;3337:1;3334;3327:12;3289:52;-1:-1:-1;3360:23:1;;3209:180;-1:-1:-1;3209:180:1:o;3602:315::-;3670:6;3678;3731:2;3719:9;3710:7;3706:23;3702:32;3699:52;;;3747:1;3744;3737:12;3699:52;3786:9;3773:23;3805:31;3830:5;3805:31;:::i;:::-;3855:5;3907:2;3892:18;;;;3879:32;;-1:-1:-1;;;3602:315:1:o;3922:127::-;3983:10;3978:3;3974:20;3971:1;3964:31;4014:4;4011:1;4004:15;4038:4;4035:1;4028:15;4054:342;4200:2;4185:18;;4233:1;4222:13;;4212:144;;4278:10;4273:3;4269:20;4266:1;4259:31;4313:4;4310:1;4303:15;4341:4;4338:1;4331:15;4212:144;4365:25;;;4054:342;:::o;4583:456::-;4660:6;4668;4676;4729:2;4717:9;4708:7;4704:23;4700:32;4697:52;;;4745:1;4742;4735:12;4697:52;4784:9;4771:23;4803:31;4828:5;4803:31;:::i;:::-;4853:5;-1:-1:-1;4910:2:1;4895:18;;4882:32;4923:33;4882:32;4923:33;:::i;:::-;4583:456;;4975:7;;-1:-1:-1;;;5029:2:1;5014:18;;;;5001:32;;4583:456::o;5044:796::-;5141:6;5149;5157;5165;5173;5226:3;5214:9;5205:7;5201:23;5197:33;5194:53;;;5243:1;5240;5233:12;5194:53;5279:9;5266:23;5256:33;;5336:2;5325:9;5321:18;5308:32;5298:42;;5387:2;5376:9;5372:18;5359:32;5349:42;;5442:2;5431:9;5427:18;5414:32;5465:18;5506:2;5498:6;5495:14;5492:34;;;5522:1;5519;5512:12;5492:34;5560:6;5549:9;5545:22;5535:32;;5605:7;5598:4;5594:2;5590:13;5586:27;5576:55;;5627:1;5624;5617:12;5576:55;5667:2;5654:16;5693:2;5685:6;5682:14;5679:34;;;5709:1;5706;5699:12;5679:34;5754:7;5749:2;5740:6;5736:2;5732:15;5728:24;5725:37;5722:57;;;5775:1;5772;5765:12;5722:57;5044:796;;;;-1:-1:-1;5044:796:1;;-1:-1:-1;5806:2:1;5798:11;;5828:6;5044:796;-1:-1:-1;;;5044:796:1:o;5845:315::-;5913:6;5921;5974:2;5962:9;5953:7;5949:23;5945:32;5942:52;;;5990:1;5987;5980:12;5942:52;6026:9;6013:23;6003:33;;6086:2;6075:9;6071:18;6058:32;6099:31;6124:5;6099:31;:::i;:::-;6149:5;6139:15;;;5845:315;;;;;:::o;6165:270::-;6238:6;6291:2;6279:9;6270:7;6266:23;6262:32;6259:52;;;6307:1;6304;6297:12;6259:52;6346:9;6333:23;6385:1;6378:5;6375:12;6365:40;;6401:1;6398;6391:12;6909:118;6995:5;6988:13;6981:21;6974:5;6971:32;6961:60;;7017:1;7014;7007:12;7032:241;7088:6;7141:2;7129:9;7120:7;7116:23;7112:32;7109:52;;;7157:1;7154;7147:12;7109:52;7196:9;7183:23;7215:28;7237:5;7215:28;:::i;7606:382::-;7671:6;7679;7732:2;7720:9;7711:7;7707:23;7703:32;7700:52;;;7748:1;7745;7738:12;7700:52;7787:9;7774:23;7806:31;7831:5;7806:31;:::i;:::-;7856:5;-1:-1:-1;7913:2:1;7898:18;;7885:32;7926:30;7885:32;7926:30;:::i;7993:795::-;8088:6;8096;8104;8112;8165:3;8153:9;8144:7;8140:23;8136:33;8133:53;;;8182:1;8179;8172:12;8133:53;8221:9;8208:23;8240:31;8265:5;8240:31;:::i;:::-;8290:5;-1:-1:-1;8347:2:1;8332:18;;8319:32;8360:33;8319:32;8360:33;:::i;:::-;8412:7;-1:-1:-1;8466:2:1;8451:18;;8438:32;;-1:-1:-1;8521:2:1;8506:18;;8493:32;8548:18;8537:30;;8534:50;;;8580:1;8577;8570:12;8534:50;8603:22;;8656:4;8648:13;;8644:27;-1:-1:-1;8634:55:1;;8685:1;8682;8675:12;8634:55;8708:74;8774:7;8769:2;8756:16;8751:2;8747;8743:11;8708:74;:::i;:::-;8698:84;;;7993:795;;;;;;;:::o;8793:388::-;8861:6;8869;8922:2;8910:9;8901:7;8897:23;8893:32;8890:52;;;8938:1;8935;8928:12;8890:52;8977:9;8964:23;8996:31;9021:5;8996:31;:::i;:::-;9046:5;-1:-1:-1;9103:2:1;9088:18;;9075:32;9116:33;9075:32;9116:33;:::i;9186:356::-;9388:2;9370:21;;;9407:18;;;9400:30;9466:34;9461:2;9446:18;;9439:62;9533:2;9518:18;;9186:356::o;9547:276::-;9678:3;9716:6;9710:13;9732:53;9778:6;9773:3;9766:4;9758:6;9754:17;9732:53;:::i;:::-;9801:16;;;;;9547:276;-1:-1:-1;;9547:276:1:o;9828:340::-;10030:2;10012:21;;;10069:2;10049:18;;;10042:30;-1:-1:-1;;;10103:2:1;10088:18;;10081:46;10159:2;10144:18;;9828:340::o;10510:380::-;10589:1;10585:12;;;;10632;;;10653:61;;10707:4;10699:6;10695:17;10685:27;;10653:61;10760:2;10752:6;10749:14;10729:18;10726:38;10723:161;;10806:10;10801:3;10797:20;10794:1;10787:31;10841:4;10838:1;10831:15;10869:4;10866:1;10859:15;10723:161;;10510:380;;;:::o;11174:245::-;11241:6;11294:2;11282:9;11273:7;11269:23;11265:32;11262:52;;;11310:1;11307;11300:12;11262:52;11342:9;11336:16;11361:28;11383:5;11361:28;:::i;11424:338::-;11626:2;11608:21;;;11665:2;11645:18;;;11638:30;-1:-1:-1;;;11699:2:1;11684:18;;11677:44;11753:2;11738:18;;11424:338::o;11767:336::-;11969:2;11951:21;;;12008:2;11988:18;;;11981:30;-1:-1:-1;;;12042:2:1;12027:18;;12020:42;12094:2;12079:18;;11767:336::o;12784:734::-;-1:-1:-1;;;;;13091:15:1;;;13073:34;;13143:15;;13138:2;13123:18;;13116:43;13190:2;13175:18;;13168:34;;;13233:2;13218:18;;13211:34;;;13053:3;13276;13261:19;;13254:32;;;13302:19;;13295:35;;;13016:4;13323:6;13373;13367:3;13352:19;;13339:49;13438:1;13432:3;13423:6;13412:9;13408:22;13404:32;13397:43;13508:3;13501:2;13497:7;13492:2;13484:6;13480:15;13476:29;13465:9;13461:45;13457:55;13449:63;;12784:734;;;;;;;;;:::o;13865:127::-;13926:10;13921:3;13917:20;13914:1;13907:31;13957:4;13954:1;13947:15;13981:4;13978:1;13971:15;13997:128;14037:3;14068:1;14064:6;14061:1;14058:13;14055:39;;;14074:18;;:::i;:::-;-1:-1:-1;14110:9:1;;13997:128::o;14804:355::-;15006:2;14988:21;;;15045:2;15025:18;;;15018:30;15084:33;15079:2;15064:18;;15057:61;15150:2;15135:18;;14804:355::o;15164:251::-;15234:6;15287:2;15275:9;15266:7;15262:23;15258:32;15255:52;;;15303:1;15300;15293:12;15255:52;15335:9;15329:16;15354:31;15379:5;15354:31;:::i;15894:168::-;15934:7;16000:1;15996;15992:6;15988:14;15985:1;15982:21;15977:1;15970:9;15963:17;15959:45;15956:71;;;16007:18;;:::i;:::-;-1:-1:-1;16047:9:1;;15894:168::o;16402:470::-;16581:3;16619:6;16613:13;16635:53;16681:6;16676:3;16669:4;16661:6;16657:17;16635:53;:::i;:::-;16751:13;;16710:16;;;;16773:57;16751:13;16710:16;16807:4;16795:17;;16773:57;:::i;:::-;16846:20;;16402:470;-1:-1:-1;;;;16402:470:1:o;18480:125::-;18520:4;18548:1;18545;18542:8;18539:34;;;18553:18;;:::i;:::-;-1:-1:-1;18590:9:1;;18480:125::o;18610:135::-;18649:3;18670:17;;;18667:43;;18690:18;;:::i;:::-;-1:-1:-1;18737:1:1;18726:13;;18610:135::o;18750:332::-;18952:2;18934:21;;;18991:1;18971:18;;;18964:29;-1:-1:-1;;;19024:2:1;19009:18;;19002:39;19073:2;19058:18;;18750:332::o;19475:184::-;19545:6;19598:2;19586:9;19577:7;19573:23;19569:32;19566:52;;;19614:1;19611;19604:12;19566:52;-1:-1:-1;19637:16:1;;19475:184;-1:-1:-1;19475:184:1:o;20675:127::-;20736:10;20731:3;20727:20;20724:1;20717:31;20767:4;20764:1;20757:15;20791:4;20788:1;20781:15;20807:120;20847:1;20873;20863:35;;20878:18;;:::i;:::-;-1:-1:-1;20912:9:1;;20807:120::o;21282:489::-;-1:-1:-1;;;;;21551:15:1;;;21533:34;;21603:15;;21598:2;21583:18;;21576:43;21650:2;21635:18;;21628:34;;;21698:3;21693:2;21678:18;;21671:31;;;21476:4;;21719:46;;21745:19;;21737:6;21719:46;:::i;:::-;21711:54;21282:489;-1:-1:-1;;;;;;21282:489:1:o;21776:249::-;21845:6;21898:2;21886:9;21877:7;21873:23;21869:32;21866:52;;;21914:1;21911;21904:12;21866:52;21946:9;21940:16;21965:30;21989:5;21965:30;:::i;22030:112::-;22062:1;22088;22078:35;;22093:18;;:::i;:::-;-1:-1:-1;22127:9:1;;22030:112::o;22147:127::-;22208:10;22203:3;22199:20;22196:1;22189:31;22239:4;22236:1;22229:15;22263:4;22260:1;22253:15;22965:644;23217:4;23263:1;23259;23254:3;23250:11;23246:19;23304:2;23296:6;23292:15;23281:9;23274:34;23344:6;23339:2;23328:9;23324:18;23317:34;23387:3;23382:2;23371:9;23367:18;23360:31;23408:46;23449:3;23438:9;23434:19;23426:6;23408:46;:::i;:::-;23490:15;;;23485:2;23470:18;;23463:43;23537:3;23522:19;;23515:35;;;;-1:-1:-1;23587:15:1;;23581:3;23566:19;;;23559:44;23400:54;22965:644;-1:-1:-1;;;22965:644:1:o

Swarm Source

ipfs://ca5d34997d0bcb7d02d6521d8dba33d9fdfbb35791cf0bb0142a9c4543586c1a
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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