ETH Price: $3,640.22 (-1.30%)

Token

veNFT (veNFT)

Overview

Max Total Supply

1,470,741,106.926646830160398489 veNFT

Holders

6,977

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
0.000000000000000001 veNFT
0x1abb1a6d682f7c796faae97f656340f08ac69417
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
VotingEscrow

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 optimistic.etherscan.io on 2022-06-01
*/

// File: contracts/interfaces/IVotingEscrow.sol

pragma solidity 0.8.13;

interface IVotingEscrow {

    struct Point {
        int128 bias;
        int128 slope; // # -dweight / dt
        uint256 ts;
        uint256 blk; // block
    }

    function token() external view returns (address);
    function team() external returns (address);
    function epoch() external view returns (uint);
    function point_history(uint loc) external view returns (Point memory);
    function user_point_history(uint tokenId, uint loc) external view returns (Point memory);
    function user_point_epoch(uint tokenId) external view returns (uint);

    function ownerOf(uint) external view returns (address);
    function isApprovedOrOwner(address, uint) external view returns (bool);
    function transferFrom(address, address, uint) external;

    function voting(uint tokenId) external;
    function abstain(uint tokenId) external;
    function attach(uint tokenId) external;
    function detach(uint tokenId) external;

    function checkpoint() external;
    function deposit_for(uint tokenId, uint value) external;
    function create_lock_for(uint, uint, address) external returns (uint);

    function balanceOfNFT(uint) external view returns (uint);
    function totalSupply() external view returns (uint);
}

// File: contracts/interfaces/IVeArtProxy.sol

pragma solidity 0.8.13;

interface IVeArtProxy {
    function _tokenURI(uint _tokenId, uint _balanceOf, uint _locked_end, uint _value) external pure returns (string memory output);
}

// File: contracts/interfaces/IERC20.sol

pragma solidity 0.8.13;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function transfer(address recipient, uint amount) external returns (bool);
    function decimals() external view returns (uint8);
    function symbol() external view returns (string memory);
    function balanceOf(address) external view returns (uint);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint value) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

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


// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

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

// File: openzeppelin-contracts/contracts/governance/utils/IVotes.sol


// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.0;

/**
 * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
 *
 * _Available since v4.5._
 */
interface IVotes {
    /**
     * @dev Emitted when an account changes their delegate.
     */
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);

    /**
     * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
     */
    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);

    /**
     * @dev Returns the current amount of votes that `account` has.
     */
    function getVotes(address account) external view returns (uint256);

    /**
     * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
     */
    function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);

    /**
     * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
     *
     * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
     * Votes that have not been delegated are still part of total supply, even though they would not participate in a
     * vote.
     */
    function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);

    /**
     * @dev Returns the delegate that `account` has chosen.
     */
    function delegates(address account) external view returns (address);

    /**
     * @dev Delegates votes from the sender to `delegatee`.
     */
    function delegate(address delegatee) external;

    /**
     * @dev Delegates votes from signer to `delegatee`.
     */
    function delegateBySig(
        address delegatee,
        uint256 nonce,
        uint256 expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

// File: openzeppelin-contracts/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/contracts/token/ERC721/IERC721.sol


// OpenZeppelin Contracts (last updated v4.6.0) (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`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: 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 Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

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

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

// File: openzeppelin-contracts/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/VotingEscrow.sol


pragma solidity 0.8.13;







/// @title Voting Escrow
/// @notice veNFT implementation that escrows ERC-20 tokens in the form of an ERC-721 NFT
/// @notice Votes have a weight depending on time, so that users are committed to the future of (whatever they are voting for)
/// @author Modified from Solidly (https://github.com/solidlyexchange/solidly/blob/master/contracts/ve.sol)
/// @author Modified from Curve (https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy)
/// @author Modified from Nouns DAO (https://github.com/withtally/my-nft-dao-project/blob/main/contracts/ERC721Checkpointable.sol)
/// @dev Vote weight decays linearly over time. Lock time cannot be more than `MAXTIME` (4 years).
contract VotingEscrow is IERC721, IERC721Metadata, IVotes {
    enum DepositType {
        DEPOSIT_FOR_TYPE,
        CREATE_LOCK_TYPE,
        INCREASE_LOCK_AMOUNT,
        INCREASE_UNLOCK_TIME,
        MERGE_TYPE
    }

    struct LockedBalance {
        int128 amount;
        uint end;
    }

    struct Point {
        int128 bias;
        int128 slope; // # -dweight / dt
        uint ts;
        uint blk; // block
    }
    /* We cannot really do block numbers per se b/c slope is per time, not per block
     * and per block could be fairly bad b/c Ethereum changes blocktimes.
     * What we can do is to extrapolate ***At functions */

    /// @notice A checkpoint for marking delegated tokenIds from a given timestamp
    struct Checkpoint {
        uint timestamp;
        uint[] tokenIds;
    }

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Deposit(
        address indexed provider,
        uint tokenId,
        uint value,
        uint indexed locktime,
        DepositType deposit_type,
        uint ts
    );
    event Withdraw(address indexed provider, uint tokenId, uint value, uint ts);
    event Supply(uint prevSupply, uint supply);

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    address public immutable token;
    address public voter;
    address public team;
    address public artProxy;

    mapping(uint => Point) public point_history; // epoch -> unsigned point

    /// @dev Mapping of interface id to bool about whether or not it's supported
    mapping(bytes4 => bool) internal supportedInterfaces;

    /// @dev ERC165 interface ID of ERC165
    bytes4 internal constant ERC165_INTERFACE_ID = 0x01ffc9a7;

    /// @dev ERC165 interface ID of ERC721
    bytes4 internal constant ERC721_INTERFACE_ID = 0x80ac58cd;

    /// @dev ERC165 interface ID of ERC721Metadata
    bytes4 internal constant ERC721_METADATA_INTERFACE_ID = 0x5b5e139f;

    /// @dev Current count of token
    uint internal tokenId;

    /// @notice Contract constructor
    /// @param token_addr `VELO` token address
    constructor(address token_addr, address art_proxy) {
        token = token_addr;
        voter = msg.sender;
        team = msg.sender;
        artProxy = art_proxy;

        point_history[0].blk = block.number;
        point_history[0].ts = block.timestamp;

        supportedInterfaces[ERC165_INTERFACE_ID] = true;
        supportedInterfaces[ERC721_INTERFACE_ID] = true;
        supportedInterfaces[ERC721_METADATA_INTERFACE_ID] = true;

        // mint-ish
        emit Transfer(address(0), address(this), tokenId);
        // burn-ish
        emit Transfer(address(this), address(0), tokenId);
    }

    /*//////////////////////////////////////////////////////////////
                                MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /// @dev reentrancy guard
    uint8 internal constant _not_entered = 1;
    uint8 internal constant _entered = 2;
    uint8 internal _entered_state = 1;
    modifier nonreentrant() {
        require(_entered_state == _not_entered);
        _entered_state = _entered;
        _;
        _entered_state = _not_entered;
    }

    /*///////////////////////////////////////////////////////////////
                             METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string constant public name = "veNFT";
    string constant public symbol = "veNFT";
    string constant public version = "1.0.0";
    uint8 constant public decimals = 18;

    function setTeam(address _team) external {
        require(msg.sender == team);
        team = _team;
    }

    function setArtProxy(address _proxy) external {
        require(msg.sender == team);
        artProxy = _proxy;
    }

    /// @dev Returns current token URI metadata
    /// @param _tokenId Token ID to fetch URI for.
    function tokenURI(uint _tokenId) external view returns (string memory) {
        require(idToOwner[_tokenId] != address(0), "Query for nonexistent token");
        LockedBalance memory _locked = locked[_tokenId];
        return IVeArtProxy(artProxy)._tokenURI(
            _tokenId,
            _balanceOfNFT(_tokenId, block.timestamp),
            _locked.end,
            uint(int256(_locked.amount))
        );
    }

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    /// @dev Mapping from NFT ID to the address that owns it.
    mapping(uint => address) internal idToOwner;

    /// @dev Mapping from owner address to count of his tokens.
    mapping(address => uint) internal ownerToNFTokenCount;

    /// @dev Returns the address of the owner of the NFT.
    /// @param _tokenId The identifier for an NFT.
    function ownerOf(uint _tokenId) public view returns (address) {
        return idToOwner[_tokenId];
    }

    /// @dev Returns the number of NFTs owned by `_owner`.
    ///      Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid.
    /// @param _owner Address for whom to query the balance.
    function _balance(address _owner) internal view returns (uint) {
        return ownerToNFTokenCount[_owner];
    }

    /// @dev Returns the number of NFTs owned by `_owner`.
    ///      Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid.
    /// @param _owner Address for whom to query the balance.
    function balanceOf(address _owner) external view returns (uint) {
        return _balance(_owner);
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    /// @dev Mapping from NFT ID to approved address.
    mapping(uint => address) internal idToApprovals;

    /// @dev Mapping from owner address to mapping of operator addresses.
    mapping(address => mapping(address => bool)) internal ownerToOperators;

    mapping(uint => uint) public ownership_change;

    /// @dev Get the approved address for a single NFT.
    /// @param _tokenId ID of the NFT to query the approval of.
    function getApproved(uint _tokenId) external view returns (address) {
        return idToApprovals[_tokenId];
    }

    /// @dev Checks if `_operator` is an approved operator for `_owner`.
    /// @param _owner The address that owns the NFTs.
    /// @param _operator The address that acts on behalf of the owner.
    function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
        return (ownerToOperators[_owner])[_operator];
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @dev Set or reaffirm the approved address for an NFT. The zero address indicates there is no approved address.
    ///      Throws unless `msg.sender` is the current NFT owner, or an authorized operator of the current owner.
    ///      Throws if `_tokenId` is not a valid NFT. (NOTE: This is not written the EIP)
    ///      Throws if `_approved` is the current owner. (NOTE: This is not written the EIP)
    /// @param _approved Address to be approved for the given NFT ID.
    /// @param _tokenId ID of the token to be approved.
    function approve(address _approved, uint _tokenId) public {
        address owner = idToOwner[_tokenId];
        // Throws if `_tokenId` is not a valid NFT
        require(owner != address(0));
        // Throws if `_approved` is the current owner
        require(_approved != owner);
        // Check requirements
        bool senderIsOwner = (idToOwner[_tokenId] == msg.sender);
        bool senderIsApprovedForAll = (ownerToOperators[owner])[msg.sender];
        require(senderIsOwner || senderIsApprovedForAll);
        // Set the approval
        idToApprovals[_tokenId] = _approved;
        emit Approval(owner, _approved, _tokenId);
    }

    /// @dev Enables or disables approval for a third party ("operator") to manage all of
    ///      `msg.sender`'s assets. It also emits the ApprovalForAll event.
    ///      Throws if `_operator` is the `msg.sender`. (NOTE: This is not written the EIP)
    /// @notice This works even if sender doesn't own any tokens at the time.
    /// @param _operator Address to add to the set of authorized operators.
    /// @param _approved True if the operators is approved, false to revoke approval.
    function setApprovalForAll(address _operator, bool _approved) external {
        // Throws if `_operator` is the `msg.sender`
        assert(_operator != msg.sender);
        ownerToOperators[msg.sender][_operator] = _approved;
        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    /* TRANSFER FUNCTIONS */
    /// @dev Clear an approval of a given address
    ///      Throws if `_owner` is not the current owner.
    function _clearApproval(address _owner, uint _tokenId) internal {
        // Throws if `_owner` is not the current owner
        assert(idToOwner[_tokenId] == _owner);
        if (idToApprovals[_tokenId] != address(0)) {
            // Reset approvals
            idToApprovals[_tokenId] = address(0);
        }
    }

    /// @dev Returns whether the given spender can transfer a given token ID
    /// @param _spender address of the spender to query
    /// @param _tokenId uint ID of the token to be transferred
    /// @return bool whether the msg.sender is approved for the given token ID, is an operator of the owner, or is the owner of the token
    function _isApprovedOrOwner(address _spender, uint _tokenId) internal view returns (bool) {
        address owner = idToOwner[_tokenId];
        bool spenderIsOwner = owner == _spender;
        bool spenderIsApproved = _spender == idToApprovals[_tokenId];
        bool spenderIsApprovedForAll = (ownerToOperators[owner])[_spender];
        return spenderIsOwner || spenderIsApproved || spenderIsApprovedForAll;
    }

    function isApprovedOrOwner(address _spender, uint _tokenId) external view returns (bool) {
        return _isApprovedOrOwner(_spender, _tokenId);
    }

    /// @dev Exeute transfer of a NFT.
    ///      Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
    ///      address for this NFT. (NOTE: `msg.sender` not allowed in internal function so pass `_sender`.)
    ///      Throws if `_to` is the zero address.
    ///      Throws if `_from` is not the current owner.
    ///      Throws if `_tokenId` is not a valid NFT.
    function _transferFrom(
        address _from,
        address _to,
        uint _tokenId,
        address _sender
    ) internal {
        require(attachments[_tokenId] == 0 && !voted[_tokenId], "attached");
        // Check requirements
        require(_isApprovedOrOwner(_sender, _tokenId));
        // Clear approval. Throws if `_from` is not the current owner
        _clearApproval(_from, _tokenId);
        // Remove NFT. Throws if `_tokenId` is not a valid NFT
        _removeTokenFrom(_from, _tokenId);
        // auto re-delegate
        _moveTokenDelegates(delegates(_from), delegates(_to), _tokenId);
        // Add NFT
        _addTokenTo(_to, _tokenId);
        // Set the block of ownership transfer (for Flash NFT protection)
        ownership_change[_tokenId] = block.number;
        // Log the transfer
        emit Transfer(_from, _to, _tokenId);
    }

    /// @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved address for this NFT.
    ///      Throws if `_from` is not the current owner.
    ///      Throws if `_to` is the zero address.
    ///      Throws if `_tokenId` is not a valid NFT.
    /// @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
    ///        they maybe be permanently lost.
    /// @param _from The current owner of the NFT.
    /// @param _to The new owner.
    /// @param _tokenId The NFT to transfer.
    function transferFrom(
        address _from,
        address _to,
        uint _tokenId
    ) external {
        _transferFrom(_from, _to, _tokenId, msg.sender);
    }

    /// @dev Transfers the ownership of an NFT from one address to another address.
    ///      Throws unless `msg.sender` is the current owner, an authorized operator, or the
    ///      approved address for this NFT.
    ///      Throws if `_from` is not the current owner.
    ///      Throws if `_to` is the zero address.
    ///      Throws if `_tokenId` is not a valid NFT.
    ///      If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if
    ///      the return value is not `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`.
    /// @param _from The current owner of the NFT.
    /// @param _to The new owner.
    /// @param _tokenId The NFT to transfer.
    function safeTransferFrom(
        address _from,
        address _to,
        uint _tokenId
    ) external {
        safeTransferFrom(_from, _to, _tokenId, "");
    }

    function _isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.
        uint size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /// @dev Transfers the ownership of an NFT from one address to another address.
    ///      Throws unless `msg.sender` is the current owner, an authorized operator, or the
    ///      approved address for this NFT.
    ///      Throws if `_from` is not the current owner.
    ///      Throws if `_to` is the zero address.
    ///      Throws if `_tokenId` is not a valid NFT.
    ///      If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if
    ///      the return value is not `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`.
    /// @param _from The current owner of the NFT.
    /// @param _to The new owner.
    /// @param _tokenId The NFT to transfer.
    /// @param _data Additional data with no specified format, sent in call to `_to`.
    function safeTransferFrom(
        address _from,
        address _to,
        uint _tokenId,
        bytes memory _data
    ) public {
        _transferFrom(_from, _to, _tokenId, msg.sender);

        if (_isContract(_to)) {
            // Throws if transfer destination is a contract which does not implement 'onERC721Received'
            try IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) returns (bytes4 response) {
                if (response != IERC721Receiver(_to).onERC721Received.selector) {
                    revert("ERC721: ERC721Receiver rejected tokens");
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert('ERC721: transfer to non ERC721Receiver implementer');
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @dev Interface identification is specified in ERC-165.
    /// @param _interfaceID Id of the interface
    function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
        return supportedInterfaces[_interfaceID];
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @dev Mapping from owner address to mapping of index to tokenIds
    mapping(address => mapping(uint => uint)) internal ownerToNFTokenIdList;

    /// @dev Mapping from NFT ID to index of owner
    mapping(uint => uint) internal tokenToOwnerIndex;

    /// @dev  Get token by index
    function tokenOfOwnerByIndex(address _owner, uint _tokenIndex) external view returns (uint) {
        return ownerToNFTokenIdList[_owner][_tokenIndex];
    }

    /// @dev Add a NFT to an index mapping to a given address
    /// @param _to address of the receiver
    /// @param _tokenId uint ID Of the token to be added
    function _addTokenToOwnerList(address _to, uint _tokenId) internal {
        uint current_count = _balance(_to);

        ownerToNFTokenIdList[_to][current_count] = _tokenId;
        tokenToOwnerIndex[_tokenId] = current_count;
    }

    /// @dev Add a NFT to a given address
    ///      Throws if `_tokenId` is owned by someone.
    function _addTokenTo(address _to, uint _tokenId) internal {
        // Throws if `_tokenId` is owned by someone
        assert(idToOwner[_tokenId] == address(0));
        // Change the owner
        idToOwner[_tokenId] = _to;
        // Update owner token index tracking
        _addTokenToOwnerList(_to, _tokenId);
        // Change count tracking
        ownerToNFTokenCount[_to] += 1;
    }

    /// @dev Function to mint tokens
    ///      Throws if `_to` is zero address.
    ///      Throws if `_tokenId` is owned by someone.
    /// @param _to The address that will receive the minted tokens.
    /// @param _tokenId The token id to mint.
    /// @return A boolean that indicates if the operation was successful.
    function _mint(address _to, uint _tokenId) internal returns (bool) {
        // Throws if `_to` is zero address
        assert(_to != address(0));
        // checkpoint for gov
        _moveTokenDelegates(address(0), delegates(_to), _tokenId);
        // Add NFT. Throws if `_tokenId` is owned by someone
        _addTokenTo(_to, _tokenId);
        emit Transfer(address(0), _to, _tokenId);
        return true;
    }

    /// @dev Remove a NFT from an index mapping to a given address
    /// @param _from address of the sender
    /// @param _tokenId uint ID Of the token to be removed
    function _removeTokenFromOwnerList(address _from, uint _tokenId) internal {
        // Delete
        uint current_count = _balance(_from) - 1;
        uint current_index = tokenToOwnerIndex[_tokenId];

        if (current_count == current_index) {
            // update ownerToNFTokenIdList
            ownerToNFTokenIdList[_from][current_count] = 0;
            // update tokenToOwnerIndex
            tokenToOwnerIndex[_tokenId] = 0;
        } else {
            uint lastTokenId = ownerToNFTokenIdList[_from][current_count];

            // Add
            // update ownerToNFTokenIdList
            ownerToNFTokenIdList[_from][current_index] = lastTokenId;
            // update tokenToOwnerIndex
            tokenToOwnerIndex[lastTokenId] = current_index;

            // Delete
            // update ownerToNFTokenIdList
            ownerToNFTokenIdList[_from][current_count] = 0;
            // update tokenToOwnerIndex
            tokenToOwnerIndex[_tokenId] = 0;
        }
    }

    /// @dev Remove a NFT from a given address
    ///      Throws if `_from` is not the current owner.
    function _removeTokenFrom(address _from, uint _tokenId) internal {
        // Throws if `_from` is not the current owner
        assert(idToOwner[_tokenId] == _from);
        // Change the owner
        idToOwner[_tokenId] = address(0);
        // Update owner token index tracking
        _removeTokenFromOwnerList(_from, _tokenId);
        // Change count tracking
        ownerToNFTokenCount[_from] -= 1;
    }

    function _burn(uint _tokenId) internal {
        require(_isApprovedOrOwner(msg.sender, _tokenId), "caller is not owner nor approved");

        address owner = ownerOf(_tokenId);

        // Clear approval
        approve(address(0), _tokenId);
        // checkpoint for gov
        _moveTokenDelegates(delegates(owner), address(0), _tokenId);
        // Remove token
        _removeTokenFrom(msg.sender, _tokenId);
        emit Transfer(owner, address(0), _tokenId);
    }

    /*//////////////////////////////////////////////////////////////
                             ESCROW STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint => uint) public user_point_epoch;
    mapping(uint => Point[1000000000]) public user_point_history; // user -> Point[user_epoch]
    mapping(uint => LockedBalance) public locked;
    uint public epoch;
    mapping(uint => int128) public slope_changes; // time -> signed slope change
    uint public supply;

    uint internal constant WEEK = 1 weeks;
    uint internal constant MAXTIME = 4 * 365 * 86400;
    int128 internal constant iMAXTIME = 4 * 365 * 86400;
    uint internal constant MULTIPLIER = 1 ether;

    /*//////////////////////////////////////////////////////////////
                              ESCROW LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @notice Get the most recently recorded rate of voting power decrease for `_tokenId`
    /// @param _tokenId token of the NFT
    /// @return Value of the slope
    function get_last_user_slope(uint _tokenId) external view returns (int128) {
        uint uepoch = user_point_epoch[_tokenId];
        return user_point_history[_tokenId][uepoch].slope;
    }

    /// @notice Get the timestamp for checkpoint `_idx` for `_tokenId`
    /// @param _tokenId token of the NFT
    /// @param _idx User epoch number
    /// @return Epoch time of the checkpoint
    function user_point_history__ts(uint _tokenId, uint _idx) external view returns (uint) {
        return user_point_history[_tokenId][_idx].ts;
    }

    /// @notice Get timestamp when `_tokenId`'s lock finishes
    /// @param _tokenId User NFT
    /// @return Epoch time of the lock end
    function locked__end(uint _tokenId) external view returns (uint) {
        return locked[_tokenId].end;
    }

    /// @notice Record global and per-user data to checkpoint
    /// @param _tokenId NFT token ID. No user checkpoint if 0
    /// @param old_locked Pevious locked amount / end lock time for the user
    /// @param new_locked New locked amount / end lock time for the user
    function _checkpoint(
        uint _tokenId,
        LockedBalance memory old_locked,
        LockedBalance memory new_locked
    ) internal {
        Point memory u_old;
        Point memory u_new;
        int128 old_dslope = 0;
        int128 new_dslope = 0;
        uint _epoch = epoch;

        if (_tokenId != 0) {
            // Calculate slopes and biases
            // Kept at zero when they have to
            if (old_locked.end > block.timestamp && old_locked.amount > 0) {
                u_old.slope = old_locked.amount / iMAXTIME;
                u_old.bias = u_old.slope * int128(int256(old_locked.end - block.timestamp));
            }
            if (new_locked.end > block.timestamp && new_locked.amount > 0) {
                u_new.slope = new_locked.amount / iMAXTIME;
                u_new.bias = u_new.slope * int128(int256(new_locked.end - block.timestamp));
            }

            // Read values of scheduled changes in the slope
            // old_locked.end can be in the past and in the future
            // new_locked.end can ONLY by in the FUTURE unless everything expired: than zeros
            old_dslope = slope_changes[old_locked.end];
            if (new_locked.end != 0) {
                if (new_locked.end == old_locked.end) {
                    new_dslope = old_dslope;
                } else {
                    new_dslope = slope_changes[new_locked.end];
                }
            }
        }

        Point memory last_point = Point({bias: 0, slope: 0, ts: block.timestamp, blk: block.number});
        if (_epoch > 0) {
            last_point = point_history[_epoch];
        }
        uint last_checkpoint = last_point.ts;
        // initial_last_point is used for extrapolation to calculate block number
        // (approximately, for *At methods) and save them
        // as we cannot figure that out exactly from inside the contract
        Point memory initial_last_point = last_point;
        uint block_slope = 0; // dblock/dt
        if (block.timestamp > last_point.ts) {
            block_slope = (MULTIPLIER * (block.number - last_point.blk)) / (block.timestamp - last_point.ts);
        }
        // If last point is already recorded in this block, slope=0
        // But that's ok b/c we know the block in such case

        // Go over weeks to fill history and calculate what the current point is
        {
            uint t_i = (last_checkpoint / WEEK) * WEEK;
            for (uint i = 0; i < 255; ++i) {
                // Hopefully it won't happen that this won't get used in 5 years!
                // If it does, users will be able to withdraw but vote weight will be broken
                t_i += WEEK;
                int128 d_slope = 0;
                if (t_i > block.timestamp) {
                    t_i = block.timestamp;
                } else {
                    d_slope = slope_changes[t_i];
                }
                last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint));
                last_point.slope += d_slope;
                if (last_point.bias < 0) {
                    // This can happen
                    last_point.bias = 0;
                }
                if (last_point.slope < 0) {
                    // This cannot happen - just in case
                    last_point.slope = 0;
                }
                last_checkpoint = t_i;
                last_point.ts = t_i;
                last_point.blk = initial_last_point.blk + (block_slope * (t_i - initial_last_point.ts)) / MULTIPLIER;
                _epoch += 1;
                if (t_i == block.timestamp) {
                    last_point.blk = block.number;
                    break;
                } else {
                    point_history[_epoch] = last_point;
                }
            }
        }

        epoch = _epoch;
        // Now point_history is filled until t=now

        if (_tokenId != 0) {
            // If last point was in this block, the slope change has been applied already
            // But in such case we have 0 slope(s)
            last_point.slope += (u_new.slope - u_old.slope);
            last_point.bias += (u_new.bias - u_old.bias);
            if (last_point.slope < 0) {
                last_point.slope = 0;
            }
            if (last_point.bias < 0) {
                last_point.bias = 0;
            }
        }

        // Record the changed point into history
        point_history[_epoch] = last_point;

        if (_tokenId != 0) {
            // Schedule the slope changes (slope is going down)
            // We subtract new_user_slope from [new_locked.end]
            // and add old_user_slope to [old_locked.end]
            if (old_locked.end > block.timestamp) {
                // old_dslope was <something> - u_old.slope, so we cancel that
                old_dslope += u_old.slope;
                if (new_locked.end == old_locked.end) {
                    old_dslope -= u_new.slope; // It was a new deposit, not extension
                }
                slope_changes[old_locked.end] = old_dslope;
            }

            if (new_locked.end > block.timestamp) {
                if (new_locked.end > old_locked.end) {
                    new_dslope -= u_new.slope; // old slope disappeared at this point
                    slope_changes[new_locked.end] = new_dslope;
                }
                // else: we recorded it already in old_dslope
            }
            // Now handle user history
            uint user_epoch = user_point_epoch[_tokenId] + 1;

            user_point_epoch[_tokenId] = user_epoch;
            u_new.ts = block.timestamp;
            u_new.blk = block.number;
            user_point_history[_tokenId][user_epoch] = u_new;
        }
    }

    /// @notice Deposit and lock tokens for a user
    /// @param _tokenId NFT that holds lock
    /// @param _value Amount to deposit
    /// @param unlock_time New time when to unlock the tokens, or 0 if unchanged
    /// @param locked_balance Previous locked amount / timestamp
    /// @param deposit_type The type of deposit
    function _deposit_for(
        uint _tokenId,
        uint _value,
        uint unlock_time,
        LockedBalance memory locked_balance,
        DepositType deposit_type
    ) internal {
        LockedBalance memory _locked = locked_balance;
        uint supply_before = supply;

        supply = supply_before + _value;
        LockedBalance memory old_locked;
        (old_locked.amount, old_locked.end) = (_locked.amount, _locked.end);
        // Adding to existing lock, or if a lock is expired - creating a new one
        _locked.amount += int128(int256(_value));
        if (unlock_time != 0) {
            _locked.end = unlock_time;
        }
        locked[_tokenId] = _locked;

        // Possibilities:
        // Both old_locked.end could be current or expired (>/< block.timestamp)
        // value == 0 (extend lock) or value > 0 (add to lock or extend lock)
        // _locked.end > block.timestamp (always)
        _checkpoint(_tokenId, old_locked, _locked);

        address from = msg.sender;
        if (_value != 0 && deposit_type != DepositType.MERGE_TYPE) {
            assert(IERC20(token).transferFrom(from, address(this), _value));
        }

        emit Deposit(from, _tokenId, _value, _locked.end, deposit_type, block.timestamp);
        emit Supply(supply_before, supply_before + _value);
    }

    function block_number() external view returns (uint) {
        return block.number;
    }

    /// @notice Record global data to checkpoint
    function checkpoint() external {
        _checkpoint(0, LockedBalance(0, 0), LockedBalance(0, 0));
    }

    /// @notice Deposit `_value` tokens for `_tokenId` and add to the lock
    /// @dev Anyone (even a smart contract) can deposit for someone else, but
    ///      cannot extend their locktime and deposit for a brand new user
    /// @param _tokenId lock NFT
    /// @param _value Amount to add to user's lock
    function deposit_for(uint _tokenId, uint _value) external nonreentrant {
        LockedBalance memory _locked = locked[_tokenId];

        require(_value > 0); // dev: need non-zero value
        require(_locked.amount > 0, 'No existing lock found');
        require(_locked.end > block.timestamp, 'Cannot add to expired lock. Withdraw');
        _deposit_for(_tokenId, _value, 0, _locked, DepositType.DEPOSIT_FOR_TYPE);
    }

    /// @notice Deposit `_value` tokens for `_to` and lock for `_lock_duration`
    /// @param _value Amount to deposit
    /// @param _lock_duration Number of seconds to lock tokens for (rounded down to nearest week)
    /// @param _to Address to deposit
    function _create_lock(uint _value, uint _lock_duration, address _to) internal returns (uint) {
        uint unlock_time = (block.timestamp + _lock_duration) / WEEK * WEEK; // Locktime is rounded down to weeks

        require(_value > 0); // dev: need non-zero value
        require(unlock_time > block.timestamp, 'Can only lock until time in the future');
        require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max');

        ++tokenId;
        uint _tokenId = tokenId;
        _mint(_to, _tokenId);

        _deposit_for(_tokenId, _value, unlock_time, locked[_tokenId], DepositType.CREATE_LOCK_TYPE);
        return _tokenId;
    }

    /// @notice Deposit `_value` tokens for `msg.sender` and lock for `_lock_duration`
    /// @param _value Amount to deposit
    /// @param _lock_duration Number of seconds to lock tokens for (rounded down to nearest week)
    function create_lock(uint _value, uint _lock_duration) external nonreentrant returns (uint) {
        return _create_lock(_value, _lock_duration, msg.sender);
    }

    /// @notice Deposit `_value` tokens for `_to` and lock for `_lock_duration`
    /// @param _value Amount to deposit
    /// @param _lock_duration Number of seconds to lock tokens for (rounded down to nearest week)
    /// @param _to Address to deposit
    function create_lock_for(uint _value, uint _lock_duration, address _to) external nonreentrant returns (uint) {
        return _create_lock(_value, _lock_duration, _to);
    }

    /// @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time
    /// @param _value Amount of tokens to deposit and add to the lock
    function increase_amount(uint _tokenId, uint _value) external nonreentrant {
        assert(_isApprovedOrOwner(msg.sender, _tokenId));

        LockedBalance memory _locked = locked[_tokenId];

        assert(_value > 0); // dev: need non-zero value
        require(_locked.amount > 0, 'No existing lock found');
        require(_locked.end > block.timestamp, 'Cannot add to expired lock. Withdraw');

        _deposit_for(_tokenId, _value, 0, _locked, DepositType.INCREASE_LOCK_AMOUNT);
    }

    /// @notice Extend the unlock time for `_tokenId`
    /// @param _lock_duration New number of seconds until tokens unlock
    function increase_unlock_time(uint _tokenId, uint _lock_duration) external nonreentrant {
        assert(_isApprovedOrOwner(msg.sender, _tokenId));

        LockedBalance memory _locked = locked[_tokenId];
        uint unlock_time = (block.timestamp + _lock_duration) / WEEK * WEEK; // Locktime is rounded down to weeks

        require(_locked.end > block.timestamp, 'Lock expired');
        require(_locked.amount > 0, 'Nothing is locked');
        require(unlock_time > _locked.end, 'Can only increase lock duration');
        require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max');

        _deposit_for(_tokenId, 0, unlock_time, _locked, DepositType.INCREASE_UNLOCK_TIME);
    }

    /// @notice Withdraw all tokens for `_tokenId`
    /// @dev Only possible if the lock has expired
    function withdraw(uint _tokenId) external nonreentrant {
        assert(_isApprovedOrOwner(msg.sender, _tokenId));
        require(attachments[_tokenId] == 0 && !voted[_tokenId], "attached");

        LockedBalance memory _locked = locked[_tokenId];
        require(block.timestamp >= _locked.end, "The lock didn't expire");
        uint value = uint(int256(_locked.amount));

        locked[_tokenId] = LockedBalance(0,0);
        uint supply_before = supply;
        supply = supply_before - value;

        // old_locked can have either expired <= timestamp or zero end
        // _locked has only 0 end
        // Both can have >= 0 amount
        _checkpoint(_tokenId, _locked, LockedBalance(0,0));

        assert(IERC20(token).transfer(msg.sender, value));

        // Burn the NFT
        _burn(_tokenId);

        emit Withdraw(msg.sender, _tokenId, value, block.timestamp);
        emit Supply(supply_before, supply_before - value);
    }

    /*///////////////////////////////////////////////////////////////
                           GAUGE VOTING STORAGE
    //////////////////////////////////////////////////////////////*/

    // The following ERC20/minime-compatible methods are not real balanceOf and supply!
    // They measure the weights for the purpose of voting, so they don't represent
    // real coins.

    /// @notice Binary search to estimate timestamp for block number
    /// @param _block Block to find
    /// @param max_epoch Don't go beyond this epoch
    /// @return Approximate timestamp for block
    function _find_block_epoch(uint _block, uint max_epoch) internal view returns (uint) {
        // Binary search
        uint _min = 0;
        uint _max = max_epoch;
        for (uint i = 0; i < 128; ++i) {
            // Will be always enough for 128-bit numbers
            if (_min >= _max) {
                break;
            }
            uint _mid = (_min + _max + 1) / 2;
            if (point_history[_mid].blk <= _block) {
                _min = _mid;
            } else {
                _max = _mid - 1;
            }
        }
        return _min;
    }

    /// @notice Get the current voting power for `_tokenId`
    /// @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility
    /// @param _tokenId NFT for lock
    /// @param _t Epoch time to return voting power at
    /// @return User voting power
    function _balanceOfNFT(uint _tokenId, uint _t) internal view returns (uint) {
        uint _epoch = user_point_epoch[_tokenId];
        if (_epoch == 0) {
            return 0;
        } else {
            Point memory last_point = user_point_history[_tokenId][_epoch];
            last_point.bias -= last_point.slope * int128(int256(_t) - int256(last_point.ts));
            if (last_point.bias < 0) {
                last_point.bias = 0;
            }
            return uint(int256(last_point.bias));
        }
    }

    function balanceOfNFT(uint _tokenId) external view returns (uint) {
        if (ownership_change[_tokenId] == block.number) return 0;
        return _balanceOfNFT(_tokenId, block.timestamp);
    }

    function balanceOfNFTAt(uint _tokenId, uint _t) external view returns (uint) {
        return _balanceOfNFT(_tokenId, _t);
    }

    /// @notice Measure voting power of `_tokenId` at block height `_block`
    /// @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime
    /// @param _tokenId User's wallet NFT
    /// @param _block Block to calculate the voting power at
    /// @return Voting power
    function _balanceOfAtNFT(uint _tokenId, uint _block) internal view returns (uint) {
        // Copying and pasting totalSupply code because Vyper cannot pass by
        // reference yet
        assert(_block <= block.number);

        // Binary search
        uint _min = 0;
        uint _max = user_point_epoch[_tokenId];
        for (uint i = 0; i < 128; ++i) {
            // Will be always enough for 128-bit numbers
            if (_min >= _max) {
                break;
            }
            uint _mid = (_min + _max + 1) / 2;
            if (user_point_history[_tokenId][_mid].blk <= _block) {
                _min = _mid;
            } else {
                _max = _mid - 1;
            }
        }

        Point memory upoint = user_point_history[_tokenId][_min];

        uint max_epoch = epoch;
        uint _epoch = _find_block_epoch(_block, max_epoch);
        Point memory point_0 = point_history[_epoch];
        uint d_block = 0;
        uint d_t = 0;
        if (_epoch < max_epoch) {
            Point memory point_1 = point_history[_epoch + 1];
            d_block = point_1.blk - point_0.blk;
            d_t = point_1.ts - point_0.ts;
        } else {
            d_block = block.number - point_0.blk;
            d_t = block.timestamp - point_0.ts;
        }
        uint block_time = point_0.ts;
        if (d_block != 0) {
            block_time += (d_t * (_block - point_0.blk)) / d_block;
        }

        upoint.bias -= upoint.slope * int128(int256(block_time - upoint.ts));
        if (upoint.bias >= 0) {
            return uint(uint128(upoint.bias));
        } else {
            return 0;
        }
    }

    function balanceOfAtNFT(uint _tokenId, uint _block) external view returns (uint) {
        return _balanceOfAtNFT(_tokenId, _block);
    }

    /// @notice Calculate total voting power at some point in the past
    /// @param _block Block to calculate the total voting power at
    /// @return Total voting power at `_block`
    function totalSupplyAt(uint _block) external view returns (uint) {
        assert(_block <= block.number);
        uint _epoch = epoch;
        uint target_epoch = _find_block_epoch(_block, _epoch);

        Point memory point = point_history[target_epoch];
        uint dt = 0;
        if (target_epoch < _epoch) {
            Point memory point_next = point_history[target_epoch + 1];
            if (point.blk != point_next.blk) {
                dt = ((_block - point.blk) * (point_next.ts - point.ts)) / (point_next.blk - point.blk);
            }
        } else {
            if (point.blk != block.number) {
                dt = ((_block - point.blk) * (block.timestamp - point.ts)) / (block.number - point.blk);
            }
        }
        // Now dt contains info on how far are we beyond point
        return _supply_at(point, point.ts + dt);
    }
    /// @notice Calculate total voting power at some point in the past
    /// @param point The point (bias/slope) to start search from
    /// @param t Time to calculate the total voting power at
    /// @return Total voting power at that time
    function _supply_at(Point memory point, uint t) internal view returns (uint) {
        Point memory last_point = point;
        uint t_i = (last_point.ts / WEEK) * WEEK;
        for (uint i = 0; i < 255; ++i) {
            t_i += WEEK;
            int128 d_slope = 0;
            if (t_i > t) {
                t_i = t;
            } else {
                d_slope = slope_changes[t_i];
            }
            last_point.bias -= last_point.slope * int128(int256(t_i - last_point.ts));
            if (t_i == t) {
                break;
            }
            last_point.slope += d_slope;
            last_point.ts = t_i;
        }

        if (last_point.bias < 0) {
            last_point.bias = 0;
        }
        return uint(uint128(last_point.bias));
    }

    function totalSupply() external view returns (uint) {
        return totalSupplyAtT(block.timestamp);
    }

    /// @notice Calculate total voting power
    /// @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility
    /// @return Total voting power
    function totalSupplyAtT(uint t) public view returns (uint) {
        uint _epoch = epoch;
        Point memory last_point = point_history[_epoch];
        return _supply_at(last_point, t);
    }

    /*///////////////////////////////////////////////////////////////
                            GAUGE VOTING LOGIC
    //////////////////////////////////////////////////////////////*/

    mapping(uint => uint) public attachments;
    mapping(uint => bool) public voted;

    function setVoter(address _voter) external {
        require(msg.sender == voter);
        voter = _voter;
    }

    function voting(uint _tokenId) external {
        require(msg.sender == voter);
        voted[_tokenId] = true;
    }

    function abstain(uint _tokenId) external {
        require(msg.sender == voter);
        voted[_tokenId] = false;
    }

    function attach(uint _tokenId) external {
        require(msg.sender == voter);
        attachments[_tokenId] = attachments[_tokenId] + 1;
    }

    function detach(uint _tokenId) external {
        require(msg.sender == voter);
        attachments[_tokenId] = attachments[_tokenId] - 1;
    }

    function merge(uint _from, uint _to) external {
        require(attachments[_from] == 0 && !voted[_from], "attached");
        require(_from != _to);
        require(_isApprovedOrOwner(msg.sender, _from));
        require(_isApprovedOrOwner(msg.sender, _to));

        LockedBalance memory _locked0 = locked[_from];
        LockedBalance memory _locked1 = locked[_to];
        uint value0 = uint(int256(_locked0.amount));
        uint end = _locked0.end >= _locked1.end ? _locked0.end : _locked1.end;

        locked[_from] = LockedBalance(0, 0);
        _checkpoint(_from, _locked0, LockedBalance(0, 0));
        _burn(_from);
        _deposit_for(_to, value0, end, _locked1, DepositType.MERGE_TYPE);
    }

    /*///////////////////////////////////////////////////////////////
                            DAO VOTING STORAGE
    //////////////////////////////////////////////////////////////*/

    /// @notice The EIP-712 typehash for the contract's domain
    bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

    /// @notice The EIP-712 typehash for the delegation struct used by the contract
    bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

    /// @notice A record of each accounts delegate
    mapping(address => address) private _delegates;
    uint public constant MAX_DELEGATES = 1024; // avoid too much gas

    /// @notice A record of delegated token checkpoints for each account, by index
    mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;

    /// @notice The number of checkpoints for each account
    mapping(address => uint32) public numCheckpoints;

    /// @notice A record of states for signing / validating signatures
    mapping(address => uint) public nonces;

    /**
     * @notice Overrides the standard `Comp.sol` delegates mapping to return
     * the delegator's own address if they haven't delegated.
     * This avoids having to delegate to oneself.
     */
    function delegates(address delegator) public view returns (address) {
        address current = _delegates[delegator];
        return current == address(0) ? delegator : current;
    }

    /**
     * @notice Gets the current votes balance for `account`
     * @param account The address to get votes balance
     * @return The number of current votes for `account`
     */
    function getVotes(address account) external view returns (uint) {
        uint32 nCheckpoints = numCheckpoints[account];
        if (nCheckpoints == 0) {
            return 0;
        }
        uint[] storage _tokenIds = checkpoints[account][nCheckpoints - 1].tokenIds;
        uint votes = 0;
        for (uint i = 0; i < _tokenIds.length; i++) {
            uint tId = _tokenIds[i];
            votes = votes + _balanceOfNFT(tId, block.timestamp);
        }
        return votes;
    }

    function getPastVotesIndex(address account, uint timestamp) public view returns (uint32) {
        uint32 nCheckpoints = numCheckpoints[account];
        if (nCheckpoints == 0) {
            return 0;
        }
        // First check most recent balance
        if (checkpoints[account][nCheckpoints - 1].timestamp <= timestamp) {
            return (nCheckpoints - 1);
        }

        // Next check implicit zero balance
        if (checkpoints[account][0].timestamp > timestamp) {
            return 0;
        }

        uint32 lower = 0;
        uint32 upper = nCheckpoints - 1;
        while (upper > lower) {
            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint storage cp = checkpoints[account][center];
            if (cp.timestamp == timestamp) {
                return center;
            } else if (cp.timestamp < timestamp) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return lower;
    }

    function getPastVotes(address account, uint timestamp)
        public
        view
        returns (uint)
    {
        uint32 _checkIndex = getPastVotesIndex(account, timestamp);
        // Sum votes
        uint[] storage _tokenIds = checkpoints[account][_checkIndex].tokenIds;
        uint votes = 0;
        for (uint i = 0; i < _tokenIds.length; i++) {
            uint tId = _tokenIds[i];
            // Use the provided input timestamp here to get the right decay
            votes = votes + _balanceOfNFT(tId, timestamp);
        }
        return votes;
    }

    function getPastTotalSupply(uint256 timestamp) external view returns (uint) {
        return totalSupplyAtT(timestamp);
    }

    /*///////////////////////////////////////////////////////////////
                             DAO VOTING LOGIC
    //////////////////////////////////////////////////////////////*/

    function _moveTokenDelegates(
        address srcRep,
        address dstRep,
        uint _tokenId
    ) internal {
        if (srcRep != dstRep && _tokenId > 0) {
            if (srcRep != address(0)) {
                uint32 srcRepNum = numCheckpoints[srcRep];
                uint[] storage srcRepOld = srcRepNum > 0
                    ? checkpoints[srcRep][srcRepNum - 1].tokenIds
                    : checkpoints[srcRep][0].tokenIds;
                uint32 nextSrcRepNum = _findWhatCheckpointToWrite(srcRep);
                uint[] storage srcRepNew = checkpoints[srcRep][
                    nextSrcRepNum
                ].tokenIds;
                // All the same except _tokenId
                for (uint i = 0; i < srcRepOld.length; i++) {
                    uint tId = srcRepOld[i];
                    if (tId != _tokenId) {
                        srcRepNew.push(tId);
                    }
                }

                numCheckpoints[srcRep] = srcRepNum + 1;
            }

            if (dstRep != address(0)) {
                uint32 dstRepNum = numCheckpoints[dstRep];
                uint[] storage dstRepOld = dstRepNum > 0
                    ? checkpoints[dstRep][dstRepNum - 1].tokenIds
                    : checkpoints[dstRep][0].tokenIds;
                uint32 nextDstRepNum = _findWhatCheckpointToWrite(dstRep);
                uint[] storage dstRepNew = checkpoints[dstRep][
                    nextDstRepNum
                ].tokenIds;
                // All the same plus _tokenId
                require(
                    dstRepOld.length + 1 <= MAX_DELEGATES,
                    "dstRep would have too many tokenIds"
                );
                for (uint i = 0; i < dstRepOld.length; i++) {
                    uint tId = dstRepOld[i];
                    dstRepNew.push(tId);
                }
                dstRepNew.push(_tokenId);

                numCheckpoints[dstRep] = dstRepNum + 1;
            }
        }
    }

    function _findWhatCheckpointToWrite(address account)
        internal
        view
        returns (uint32)
    {
        uint _timestamp = block.timestamp;
        uint32 _nCheckPoints = numCheckpoints[account];

        if (
            _nCheckPoints > 0 &&
            checkpoints[account][_nCheckPoints - 1].timestamp == _timestamp
        ) {
            return _nCheckPoints - 1;
        } else {
            return _nCheckPoints;
        }
    }

    function _moveAllDelegates(
        address owner,
        address srcRep,
        address dstRep
    ) internal {
        // You can only redelegate what you own
        if (srcRep != dstRep) {
            if (srcRep != address(0)) {
                uint32 srcRepNum = numCheckpoints[srcRep];
                uint[] storage srcRepOld = srcRepNum > 0
                    ? checkpoints[srcRep][srcRepNum - 1].tokenIds
                    : checkpoints[srcRep][0].tokenIds;
                uint32 nextSrcRepNum = _findWhatCheckpointToWrite(srcRep);
                uint[] storage srcRepNew = checkpoints[srcRep][
                    nextSrcRepNum
                ].tokenIds;
                // All the same except what owner owns
                for (uint i = 0; i < srcRepOld.length; i++) {
                    uint tId = srcRepOld[i];
                    if (idToOwner[tId] != owner) {
                        srcRepNew.push(tId);
                    }
                }

                numCheckpoints[srcRep] = srcRepNum + 1;
            }

            if (dstRep != address(0)) {
                uint32 dstRepNum = numCheckpoints[dstRep];
                uint[] storage dstRepOld = dstRepNum > 0
                    ? checkpoints[dstRep][dstRepNum - 1].tokenIds
                    : checkpoints[dstRep][0].tokenIds;
                uint32 nextDstRepNum = _findWhatCheckpointToWrite(dstRep);
                uint[] storage dstRepNew = checkpoints[dstRep][
                    nextDstRepNum
                ].tokenIds;
                uint ownerTokenCount = ownerToNFTokenCount[owner];
                require(
                    dstRepOld.length + ownerTokenCount <= MAX_DELEGATES,
                    "dstRep would have too many tokenIds"
                );
                // All the same
                for (uint i = 0; i < dstRepOld.length; i++) {
                    uint tId = dstRepOld[i];
                    dstRepNew.push(tId);
                }
                // Plus all that's owned
                for (uint i = 0; i < ownerTokenCount; i++) {
                    uint tId = ownerToNFTokenIdList[owner][i];
                    dstRepNew.push(tId);
                }

                numCheckpoints[dstRep] = dstRepNum + 1;
            }
        }
    }

    function _delegate(address delegator, address delegatee) internal {
        /// @notice differs from `_delegate()` in `Comp.sol` to use `delegates` override method to simulate auto-delegation
        address currentDelegate = delegates(delegator);

        _delegates[delegator] = delegatee;

        emit DelegateChanged(delegator, currentDelegate, delegatee);
        _moveAllDelegates(delegator, currentDelegate, delegatee);
    }

    /**
     * @notice Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
    function delegate(address delegatee) public {
        if (delegatee == address(0)) delegatee = msg.sender;
        return _delegate(msg.sender, delegatee);
    }

    function delegateBySig(
        address delegatee,
        uint nonce,
        uint expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public {
        bytes32 domainSeparator = keccak256(
            abi.encode(
                DOMAIN_TYPEHASH,
                keccak256(bytes(name)),
                keccak256(bytes(version)),
                block.chainid,
                address(this)
            )
        );
        bytes32 structHash = keccak256(
            abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)
        );
        bytes32 digest = keccak256(
            abi.encodePacked("\x19\x01", domainSeparator, structHash)
        );
        address signatory = ecrecover(digest, v, r, s);
        require(
            signatory != address(0),
            "VotingEscrow::delegateBySig: invalid signature"
        );
        require(
            nonce == nonces[signatory]++,
            "VotingEscrow::delegateBySig: invalid nonce"
        );
        require(
            block.timestamp <= expiry,
            "VotingEscrow::delegateBySig: signature expired"
        );
        return _delegate(signatory, delegatee);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"token_addr","type":"address"},{"internalType":"address","name":"art_proxy","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"locktime","type":"uint256"},{"indexed":false,"internalType":"enum VotingEscrow.DepositType","name":"deposit_type","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"}],"name":"Supply","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":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DELEGATES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"abstain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_approved","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"artProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"attach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"attachments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"_block","type":"uint256"}],"name":"balanceOfAtNFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"balanceOfNFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_t","type":"uint256"}],"name":"balanceOfNFTAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"block_number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"checkpoints","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lock_duration","type":"uint256"}],"name":"create_lock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lock_duration","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"create_lock_for","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"deposit_for","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"detach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPastVotesIndex","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"get_last_user_slope","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"increase_amount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_lock_duration","type":"uint256"}],"name":"increase_unlock_time","outputs":[],"stateMutability":"nonpayable","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":"_spender","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"isApprovedOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"locked","outputs":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint256","name":"end","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"locked__end","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"}],"name":"merge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownership_change","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"point_history","outputs":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","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":"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":"_proxy","type":"address"}],"name":"setArtProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_team","type":"address"}],"name":"setTeam","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_voter","type":"address"}],"name":"setVoter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"slope_changes","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"team","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_tokenIndex","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"t","type":"uint256"}],"name":"totalSupplyAtT","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":"uint256","name":"","type":"uint256"}],"name":"user_point_epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"user_point_history","outputs":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"user_point_history__ts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"voted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"voting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040526006805460ff191660011790553480156200001e57600080fd5b5060405162004a1c38038062004a1c8339810160408190526200004191620001b8565b6001600160a01b0382811660805260008054336001600160a01b031991821681178355600180548316909117815560028054909216938516939093179055437f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92f0155427f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92f005560046020527f9fe05126d2d9ecf60592e254dead906a4b2e492f36cca727682c38e9008c6ac1805460ff1990811684179091557f4267c0a6fd96b7a87f183ee8744f24d011423cd0e0142b3f563f183d8d9a456b8054821684179055635b5e139f60e01b82527e24030bcf4927897dffe721c2d8dda4bfd8910861687c42b03a463b43b04147805490911690921790915560055460405190913091600080516020620049fc833981519152908290a46005546040516000903090600080516020620049fc833981519152908390a45050620001f0565b80516001600160a01b0381168114620001b357600080fd5b919050565b60008060408385031215620001cc57600080fd5b620001d7836200019b565b9150620001e7602084016200019b565b90509250929050565b6080516147e26200021a60003960008181610b220152818161101801526133b501526147e26000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c80637116c60c11610220578063c1f0fb9f11610130578063e7a324dc116100b8578063f1127ed811610087578063f1127ed814610abc578063f8a0576314610ae7578063fbd3a29d14610b0a578063fc0c546a14610b1d578063fd4a77f114610b4457600080fd5b8063e7a324dc14610a33578063e7e242d414610a5a578063e985e9c514610a6d578063ee99fe2814610aa957600080fd5b8063d1c2babb116100ff578063d1c2babb1461099c578063d1febfb9146109af578063d4e54c3b146109ed578063e0514aba14610a00578063e441135c14610a1357600080fd5b8063c1f0fb9f1461095b578063c2c4c5c11461096e578063c3cda52014610976578063c87b56dd1461098957600080fd5b806395d89b41116101b3578063a183af5211610182578063a183af52146108c7578063a22cb465146108da578063a4d855df146108ed578063b45a3c0e14610900578063b88d4fde1461094857600080fd5b806395d89b4114610465578063981b24d01461088e578063986b7d8a146108a15780639ab24eb0146108b457600080fd5b80638c2c9baf116101ef5780638c2c9baf1461083c5780638e539e8c1461084f5780638fbb38ff14610862578063900cf0cf1461088557600080fd5b80637116c60c146107d357806371197484146107e65780637ecebe001461080957806385f2aef21461082957600080fd5b8063313ce5671161031b5780635594a045116102ae5780636352211e1161027d5780636352211e1461073e57806365fc3873146107675780636f5488371461077a5780636fcfff451461079a57806370a08231146107c057600080fd5b80635594a045146106fc578063587cde1e1461070f5780635c19a95c146107225780635f5b0c321461073557600080fd5b8063461f711c116102ea578063461f711c1461068c57806346c96aac146106b25780634bc2a657146106c557806354fd4d50146106d857600080fd5b8063313ce567146106395780633a46b1a81461065357806342842e0e14610666578063430c20811461067957600080fd5b80631376f3da1161039e57806323b872dd1161036d57806323b872dd146105c457806325a58b56146105d75780632e1a7d4d146105dd5780632e720f7d146105f05780632f745c591461060357600080fd5b80631376f3da1461054757806318160ddd146105825780631c984bc31461058a57806320606b701461059d57600080fd5b8063081812fc116103da578063081812fc146104be578063095cf5c6146104ff578063095ea7b3146105145780630d6a20331461052757600080fd5b806301ffc9a71461040c578063047fc9aa1461044e57806306fdde03146104655780630758c7d814610496575b600080fd5b61043961041a366004613f24565b6001600160e01b03191660009081526004602052604090205460ff1690565b60405190151581526020015b60405180910390f35b61045760135481565b604051908152602001610445565b610489604051806040016040528060058152602001641d9953919560da1b81525081565b6040516104459190613f99565b6104a96104a4366004613fc8565b610b57565b60405163ffffffff9091168152602001610445565b6104e76104cc366004613ff2565b6000908152600960205260409020546001600160a01b031690565b6040516001600160a01b039091168152602001610445565b61051261050d36600461400b565b610cca565b005b610512610522366004613fc8565b610d03565b610457610535366004613ff2565b60146020526000908152604090205481565b61055a610555366004614026565b610deb565b60408051600f95860b81529390940b6020840152928201526060810191909152608001610445565b610457610e32565b610457610598366004614026565b610e42565b6104577f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6105126105d2366004614048565b610e74565b43610457565b6105126105eb366004613ff2565b610e85565b6105126105fe36600461400b565b61113b565b610457610611366004613fc8565b6001600160a01b03919091166000908152600c60209081526040808320938352929052205490565b610641601281565b60405160ff9091168152602001610445565b610457610661366004613fc8565b611174565b610512610674366004614048565b611213565b610439610687366004613fc8565b61122e565b61069f61069a366004613ff2565b611241565b604051600f9190910b8152602001610445565b6000546104e7906001600160a01b031681565b6105126106d336600461400b565b611284565b610489604051806040016040528060058152602001640312e302e360dc1b81525081565b6002546104e7906001600160a01b031681565b6104e761071d36600461400b565b6112bd565b61051261073036600461400b565b6112ed565b61045761040081565b6104e761074c366004613ff2565b6000908152600760205260409020546001600160a01b031690565b610457610775366004614026565b61130b565b610457610788366004613ff2565b600b6020526000908152604090205481565b6104a96107a836600461400b565b60186020526000908152604090205463ffffffff1681565b6104576107ce36600461400b565b61134d565b6104576107e1366004613ff2565b61136b565b61069f6107f4366004613ff2565b601260205260009081526040902054600f0b81565b61045761081736600461400b565b60196020526000908152604090205481565b6001546104e7906001600160a01b031681565b61045761084a366004614026565b6113cb565b61045761085d366004613ff2565b6113d7565b610439610870366004613ff2565b60156020526000908152604090205460ff1681565b61045760115481565b61045761089c366004613ff2565b6113e2565b6105126108af366004613ff2565b611584565b6104576108c236600461400b565b6115c8565b6105126108d5366004614026565b61169b565b6105126108e8366004614092565b61179a565b6105126108fb366004614026565b61181e565b61092e61090e366004613ff2565b60106020526000908152604090208054600190910154600f9190910b9082565b60408051600f9390930b8352602083019190915201610445565b610512610956366004614138565b611a03565b610512610969366004613ff2565b611ba2565b610512611bd1565b6105126109843660046141e3565b611c11565b610489610997366004613ff2565b611f51565b6105126109aa366004614026565b61207d565b61055a6109bd366004613ff2565b600360205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b6104576109fb366004614243565b6121e2565b610457610a0e366004614026565b612225565b610457610a21366004613ff2565b600e6020526000908152604090205481565b6104577fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b610457610a68366004613ff2565b612231565b610439610a7b366004614278565b6001600160a01b039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b610512610ab7366004614026565b612259565b610457610aca3660046142ab565b601760209081526000928352604080842090915290825290205481565b610457610af5366004613ff2565b60009081526010602052604090206001015490565b610512610b18366004613ff2565b61232d565b6104e77f000000000000000000000000000000000000000000000000000000000000000081565b610512610b52366004613ff2565b61235e565b6001600160a01b03821660009081526018602052604081205463ffffffff16808203610b87576000915050610cc4565b6001600160a01b03841660009081526017602052604081208491610bac6001856142f6565b63ffffffff16815260208101919091526040016000205411610bdb57610bd36001826142f6565b915050610cc4565b6001600160a01b0384166000908152601760209081526040808320838052909152902054831015610c10576000915050610cc4565b600080610c1e6001846142f6565b90505b8163ffffffff168163ffffffff161115610cbf5760006002610c4384846142f6565b610c4d9190614331565b610c5790836142f6565b6001600160a01b038816600090815260176020908152604080832063ffffffff851684529091529020805491925090879003610c9957509350610cc492505050565b8054871115610caa57819350610cb8565b610cb56001836142f6565b92505b5050610c21565b509150505b92915050565b6001546001600160a01b03163314610ce157600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600760205260409020546001600160a01b031680610d2557600080fd5b806001600160a01b0316836001600160a01b031603610d4357600080fd5b6000828152600760209081526040808320546001600160a01b038581168552600a845282852033808752945291909320549216149060ff168180610d845750805b610d8d57600080fd5b60008481526009602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918716917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a45050505050565b600f60205281600052604060002081633b9aca008110610e0a57600080fd5b6003020180546001820154600290920154600f82810b9550600160801b90920490910b925084565b6000610e3d4261136b565b905090565b6000828152600f6020526040812082633b9aca008110610e6457610e64614354565b6003020160010154905092915050565b610e8083838333612390565b505050565b60065460ff16600114610e9757600080fd5b6006805460ff19166002179055610eae3382612471565b610eba57610eba61436a565b600081815260146020526040902054158015610ee5575060008181526015602052604090205460ff16155b610f0a5760405162461bcd60e51b8152600401610f0190614380565b60405180910390fd5b60008181526010602090815260409182902082518084019093528054600f0b835260010154908201819052421015610f7d5760405162461bcd60e51b8152602060048201526016602482015275546865206c6f636b206469646e27742065787069726560501b6044820152606401610f01565b8051604080518082018252600080825260208083018281528783526010909152929020905181546001600160801b0319166001600160801b039091161781559051600190910155601354600f9190910b90610fd882826143a2565b6013556040805180820190915260008082526020820152610ffc90859085906124d7565b60405163a9059cbb60e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611069573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108d91906143b9565b6110995761109961436a565b6110a284612af3565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c8161111084826143a2565b6040805192835260208301919091520160405180910390a150506006805460ff191660011790555050565b6001546001600160a01b0316331461115257600080fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000806111818484610b57565b6001600160a01b038516600090815260176020908152604080832063ffffffff851684529091528120919250600190910190805b82548110156112095760008382815481106111d2576111d2614354565b906000526020600020015490506111e98188612bc6565b6111f390846143d6565b9250508080611201906143ee565b9150506111b5565b5095945050505050565b610e8083838360405180602001604052806000815250611a03565b600061123a8383612471565b9392505050565b6000818152600e6020908152604080832054600f909252822081633b9aca00811061126e5761126e614354565b6003020154600160801b9004600f0b9392505050565b6000546001600160a01b0316331461129b57600080fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0380821660009081526016602052604081205490911680156112e6578061123a565b5090919050565b6001600160a01b0381166112fe5750335b6113083382612c9a565b50565b60065460009060ff1660011461132057600080fd5b6006805460ff19166002179055611338838333612d0d565b90506006805460ff1916600117905592915050565b6001600160a01b038116600090815260086020526040812054610cc4565b601154600081815260036020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529091906113c38185612e64565b949350505050565b600061123a8383612f65565b6000610cc48261136b565b6000438211156113f4576113f461436a565b6011546000611403848361323e565b600081815260036020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152919250838310156115125760006003816114668660016143d6565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608083018290528501519192501461150c57826060015181606001516114d291906143a2565b836040015182604001516114e691906143a2565b60608501516114f5908a6143a2565b6114ff9190614407565b6115099190614426565b91505b50611561565b4382606001511461156157606082015161152c90436143a2565b604083015161153b90426143a2565b606084015161154a90896143a2565b6115549190614407565b61155e9190614426565b90505b61157a8282846040015161157591906143d6565b612e64565b9695505050505050565b6000546001600160a01b0316331461159b57600080fd5b6000818152601460205260409020546115b6906001906143a2565b60009182526014602052604090912055565b6001600160a01b03811660009081526018602052604081205463ffffffff168082036115f75750600092915050565b6001600160a01b03831660009081526017602052604081208161161b6001856142f6565b63ffffffff1663ffffffff16815260200190815260200160002060010190506000805b825481101561169257600083828154811061165b5761165b614354565b906000526020600020015490506116728142612bc6565b61167c90846143d6565b925050808061168a906143ee565b91505061163e565b50949350505050565b60065460ff166001146116ad57600080fd5b6006805460ff191660021790556116c43383612471565b6116d0576116d061436a565b60008281526010602090815260409182902082518084019093528054600f0b83526001015490820152816117065761170661436a565b60008160000151600f0b136117565760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401610f01565b428160200151116117795760405162461bcd60e51b8152600401610f019061443a565b611788838360008460026132c4565b50506006805460ff1916600117905550565b336001600160a01b038316036117b2576117b261436a565b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60065460ff1660011461183057600080fd5b6006805460ff191660021790556118473383612471565b6118535761185361436a565b600082815260106020908152604080832081518083019092528054600f0b825260010154918101919091529062093a808061188e85426143d6565b6118989190614426565b6118a29190614407565b9050428260200151116118e65760405162461bcd60e51b815260206004820152600c60248201526b131bd8dac8195e1c1a5c995960a21b6044820152606401610f01565b60008260000151600f0b136119315760405162461bcd60e51b8152602060048201526011602482015270139bdd1a1a5b99c81a5cc81b1bd8dad959607a1b6044820152606401610f01565b816020015181116119845760405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606401610f01565b611992630784ce00426143d6565b8111156119e15760405162461bcd60e51b815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006044820152606401610f01565b6119f0846000838560036132c4565b50506006805460ff191660011790555050565b611a0f84848433612390565b823b15611b9c57604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290611a4890339088908790879060040161447e565b6020604051808303816000875af1925050508015611a83575060408051601f3d908101601f19168201909252611a80918101906144b1565b60015b611b2b573d808015611ab1576040519150601f19603f3d011682016040523d82523d6000602084013e611ab6565b606091505b508051600003611b235760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610f01565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14611b9a5760405162461bcd60e51b815260206004820152602660248201527f4552433732313a2045524337323152656365697665722072656a656374656420604482015265746f6b656e7360d01b6064820152608401610f01565b505b50505050565b6000546001600160a01b03163314611bb957600080fd5b6000908152601560205260409020805460ff19169055565b611c0f600060405180604001604052806000600f0b8152602001600081525060405180604001604052806000600f0b815260200160008152506124d7565b565b6040805180820182526005808252641d9953919560da1b60209283015282518084018452908152640312e302e360dc1b9082015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fc792e9874e7b42c234d1e8448cec020a0f065019c8cd6f7ccdb65b8c110157e9818401527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c60608201524660808201523060a0808301919091528351808303909101815260c0820184528051908301207fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60e08301526001600160a01b038a1661010083015261012082018990526101408083018990528451808403909101815261016083019094528351939092019290922061190160f01b61018084015261018283018290526101a2830181905290916000906101c20160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa158015611dd0573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611e4a5760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e7660448201526d616c6964207369676e617475726560901b6064820152608401610f01565b6001600160a01b0381166000908152601960205260408120805491611e6e836143ee565b919050558914611ed35760405162461bcd60e51b815260206004820152602a60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e76604482015269616c6964206e6f6e636560b01b6064820152608401610f01565b87421115611f3a5760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a2073696760448201526d1b985d1d5c9948195e1c1a5c995960921b6064820152608401610f01565b611f44818b612c9a565b505050505b505050505050565b6000818152600760205260409020546060906001600160a01b0316611fb85760405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606401610f01565b60008281526010602090815260409182902082518084019093528054600f0b835260010154908201526002546001600160a01b031663dd9ec14984611ffd8142612bc6565b6020850151855160405160e086901b6001600160e01b0319168152600481019490945260248401929092526044830152600f0b6064820152608401600060405180830381865afa158015612055573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261123a91908101906144ce565b6000828152601460205260409020541580156120a8575060008281526015602052604090205460ff16155b6120c45760405162461bcd60e51b8152600401610f0190614380565b8082036120d057600080fd5b6120da3383612471565b6120e357600080fd5b6120ed3382612471565b6120f657600080fd5b6000828152601060208181526040808420815180830183528154600f90810b825260019283015482860190815288885295855283872084518086019095528054820b855290920154938301849052805194519095929490910b921115612160578260200151612166565b83602001515b604080518082018252600080825260208083018281528b835260108252848320935184546001600160801b0319166001600160801b03909116178455516001909301929092558251808401909352808352908201529091506121cb90879086906124d7565b6121d486612af3565b611f498583838660046132c4565b60065460009060ff166001146121f757600080fd5b6006805460ff1916600217905561220f848484612d0d565b90506006805460ff191660011790559392505050565b600061123a8383612bc6565b6000818152600b602052604081205443900361224f57506000919050565b610cc48242612bc6565b60065460ff1660011461226b57600080fd5b6006805460ff1916600217905560008281526010602090815260409182902082518084019093528054600f0b83526001015490820152816122ab57600080fd5b60008160000151600f0b136122fb5760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401610f01565b4281602001511161231e5760405162461bcd60e51b8152600401610f019061443a565b611788838360008460006132c4565b6000546001600160a01b0316331461234457600080fd5b6000818152601460205260409020546115b69060016143d6565b6000546001600160a01b0316331461237557600080fd5b6000908152601560205260409020805460ff19166001179055565b6000828152601460205260409020541580156123bb575060008281526015602052604090205460ff16155b6123d75760405162461bcd60e51b8152600401610f0190614380565b6123e18183612471565b6123ea57600080fd5b6123f484836134c9565b6123fe8483613530565b61241961240a856112bd565b612413856112bd565b846135b1565b6124238383613913565b6000828152600b60205260408082204390555183916001600160a01b0380871692908816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050565b60008181526007602090815260408083205460098352818420546001600160a01b03918216808652600a855283862088841680885295529285205492938085149392909116149060ff1682806124c45750815b806124cc5750805b979650505050505050565b6040805160808101825260008082526020820181905291810182905260608101919091526040805160808101825260008082526020820181905291810182905260608101919091526011546000908190871561264257428760200151118015612547575060008760000151600f0b135b1561258c57865161255d90630784ce009061453c565b600f0b6020808701919091528701516125779042906143a2565b8560200151612586919061457a565b600f0b85525b4286602001511180156125a6575060008660000151600f0b135b156125eb5785516125bc90630784ce009061453c565b600f0b6020808601919091528601516125d69042906143a2565b84602001516125e5919061457a565b600f0b84525b602080880151600090815260128252604090205490870151600f9190910b93501561264257866020015186602001510361262757829150612642565b602080870151600090815260129091526040902054600f0b91505b6040805160808101825260008082526020820152429181019190915243606082015281156126b7575060008181526003602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b6040810151816000428310156127045760408401516126d690426143a2565b60608501516126e590436143a2565b6126f790670de0b6b3a7640000614407565b6127019190614426565b90505b600062093a806127148186614426565b61271e9190614407565b905060005b60ff8110156128985761273962093a80836143d6565b915060004283111561274d57429250612761565b50600082815260126020526040902054600f0b5b61276b86846143a2565b876020015161277a919061457a565b8751889061278990839061460f565b600f0b9052506020870180518291906127a390839061465f565b600f90810b90915288516000910b121590506127be57600087525b60008760200151600f0b12156127d657600060208801525b60408088018490528501519295508592670de0b6b3a7640000906127fa90856143a2565b6128049086614407565b61280e9190614426565b856060015161281d91906143d6565b606088015261282d6001896143d6565b97504283036128425750436060870152612898565b6000888152600360209081526040918290208951918a01516001600160801b03908116600160801b029216919091178155908801516001820155606088015160029091015550612891816143ee565b9050612723565b505060118590558b1561292357886020015188602001516128b9919061460f565b846020018181516128ca919061465f565b600f0b905250885188516128de919061460f565b845185906128ed90839061465f565b600f90810b90915260208601516000910b1215905061290e57600060208501525b60008460000151600f0b121561292357600084525b6000858152600360209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101558b15612ae557428b6020015111156129da576020890151612989908861465f565b96508a602001518a60200151036129ac5760208801516129a9908861460f565b96505b60208b810151600090815260129091526040902080546001600160801b0319166001600160801b0389161790555b428a602001511115612a35578a602001518a602001511115612a35576020880151612a05908761460f565b60208b810151600090815260129091526040902080546001600160801b0319166001600160801b03831617905595505b60008c8152600e6020526040812054612a4f9060016143d6565b905080600e60008f815260200190815260200160002081905550428960400181815250504389606001818152505088600f60008f815260200190815260200160002082633b9aca008110612aa557612aa5614354565b825160208401516001600160801b03908116600160801b029116176003919091029190910190815560408201516001820155606090910151600290910155505b505050505050505050505050565b612afd3382612471565b612b495760405162461bcd60e51b815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665646044820152606401610f01565b6000818152600760205260408120546001600160a01b031690612b6c9083610d03565b612b80612b78826112bd565b6000846135b1565b612b8a3383613530565b60405182906000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000828152600e6020526040812054808203612be6576000915050610cc4565b6000848152600f6020526040812082633b9aca008110612c0857612c08614354565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b602083015260018101549282018390526002015460608201529150612c5490856146ae565b8160200151612c63919061457a565b81518290612c7290839061460f565b600f90810b90915282516000910b12159050612c8d57600081525b51600f0b9150610cc49050565b6000612ca5836112bd565b6001600160a01b0384811660008181526016602052604080822080546001600160a01b031916888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4610e808382846139a9565b60008062093a8080612d1f86426143d6565b612d299190614426565b612d339190614407565b905060008511612d4257600080fd5b428111612da05760405162461bcd60e51b815260206004820152602660248201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060448201526566757475726560d01b6064820152608401610f01565b612dae630784ce00426143d6565b811115612dfd5760405162461bcd60e51b815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006044820152606401610f01565b600560008154612e0c906143ee565b90915550600554612e1d8482613d65565b5060008181526010602090815260409182902082518084019093528054600f0b835260019081015491830191909152612e5b918391899186916132c4565b95945050505050565b600080839050600062093a80808360400151612e809190614426565b612e8a9190614407565b905060005b60ff811015612f3d57612ea562093a80836143d6565b9150600085831115612eb957859250612ecd565b50600082815260126020526040902054600f0b5b6040840151612edc90846143a2565b8460200151612eeb919061457a565b84518590612efa90839061460f565b600f0b905250858303612f0d5750612f3d565b8084602001818151612f1f919061465f565b600f0b9052505060408301829052612f36816143ee565b9050612e8f565b5060008260000151600f0b1215612f5357600082525b50516001600160801b03169392505050565b600043821115612f7757612f7761436a565b6000838152600e6020526040812054815b608081101561301757818310156130175760006002612fa784866143d6565b612fb29060016143d6565b612fbc9190614426565b6000888152600f60205260409020909150869082633b9aca008110612fe357612fe3614354565b600302016002015411612ff857809350613006565b6130036001826143a2565b92505b50613010816143ee565b9050612f88565b506000858152600f6020526040812083633b9aca00811061303a5761303a614354565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b60208301526001810154928201929092526002909101546060820152601154909150600061308f878361323e565b600081815260036020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152919250808484101561316e5760006003816130f38760016143d6565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606080830182905286015191925061315091906143a2565b92508360400151816040015161316691906143a2565b915050613192565b606083015161317d90436143a2565b915082604001514261318f91906143a2565b90505b604083015182156131cf578284606001518c6131ae91906143a2565b6131b89084614407565b6131c29190614426565b6131cc90826143d6565b90505b60408701516131de90826143a2565b87602001516131ed919061457a565b875188906131fc90839061460f565b600f90810b90915288516000910b12905061322c57505093516001600160801b03169650610cc495505050505050565b60009950505050505050505050610cc4565b60008082815b60808110156132ba57818310156132ba576000600261326384866143d6565b61326e9060016143d6565b6132789190614426565b600081815260036020526040902060020154909150871061329b578093506132a9565b6132a66001826143a2565b92505b506132b3816143ee565b9050613244565b5090949350505050565b60135482906132d386826143d6565b6013556040805180820190915260008082526020820152825160208085015190830152600f0b815282518790849061330c90839061465f565b600f0b905250851561332057602083018690525b6000888152601060209081526040909120845181546001600160801b0319166001600160801b03909116178155908401516001909101556133628882856124d7565b33871580159061338457506004856004811115613381576133816146ed565b14155b1561342e576040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018a90527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af11580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061342291906143b9565b61342e5761342e61436a565b8360200151816001600160a01b03167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248b8b89426040516134729493929190614703565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c836134a68a826143d6565b6040805192835260208301919091520160405180910390a1505050505050505050565b6000818152600760205260409020546001600160a01b038381169116146134f2576134f261436a565b6000818152600960205260409020546001600160a01b03161561352c57600081815260096020526040902080546001600160a01b03191690555b5050565b6000818152600760205260409020546001600160a01b038381169116146135595761355961436a565b600081815260076020526040902080546001600160a01b031916905561357f8282613dd6565b6001600160a01b03821660009081526008602052604081208054600192906135a89084906143a2565b90915550505050565b816001600160a01b0316836001600160a01b0316141580156135d35750600081115b15610e80576001600160a01b03831615613754576001600160a01b03831660009081526018602052604081205463ffffffff169081613637576001600160a01b03851660009081526017602090815260408083208380529091529020600101613679565b6001600160a01b03851660009081526017602052604081209061365b6001856142f6565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061368686613e95565b6001600160a01b038716600090815260176020908152604080832063ffffffff8516845290915281209192506001909101905b83548110156137135760008482815481106136d6576136d6614354565b90600052602060002001549050868114613700578254600181018455600084815260209020018190555b508061370b816143ee565b9150506136b9565b5061371f846001614741565b6001600160a01b0388166000908152601860205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03821615610e80576001600160a01b03821660009081526018602052604081205463ffffffff1690816137b3576001600160a01b038416600090815260176020908152604080832083805290915290206001016137f5565b6001600160a01b0384166000908152601760205260408120906137d76001856142f6565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061380285613e95565b6001600160a01b038616600090815260176020908152604080832063ffffffff85168452909152902083549192506001908101916104009161384491906143d6565b11156138625760405162461bcd60e51b8152600401610f0190614769565b60005b83548110156138b457600084828154811061388257613882614354565b6000918252602080832090910154855460018101875586845291909220015550806138ac816143ee565b915050613865565b508054600181810183556000838152602090209091018690556138d8908590614741565b6001600160a01b0387166000908152601860205260409020805463ffffffff9290921663ffffffff1990921691909117905550505050505050565b6000818152600760205260409020546001600160a01b0316156139385761393861436a565b600081815260076020908152604080832080546001600160a01b0319166001600160a01b03871690811790915580845260088084528285208054600c86528487208188528652848720889055878752600d8652938620939093559084529091528054600192906135a89084906143d6565b806001600160a01b0316826001600160a01b031614610e80576001600160a01b03821615613b5c576001600160a01b03821660009081526018602052604081205463ffffffff169081613a21576001600160a01b03841660009081526017602090815260408083208380529091529020600101613a63565b6001600160a01b038416600090815260176020526040812090613a456001856142f6565b63ffffffff1663ffffffff1681526020019081526020016000206001015b90506000613a7085613e95565b6001600160a01b038616600090815260176020908152604080832063ffffffff8516845290915281209192506001909101905b8354811015613b1b576000848281548110613ac057613ac0614354565b600091825260208083209091015480835260079091526040909120549091506001600160a01b03908116908a1614613b08578254600181018455600084815260209020018190555b5080613b13816143ee565b915050613aa3565b50613b27846001614741565b6001600160a01b0387166000908152601860205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03811615610e80576001600160a01b03811660009081526018602052604081205463ffffffff169081613bbb576001600160a01b03831660009081526017602090815260408083208380529091529020600101613bfd565b6001600160a01b038316600090815260176020526040812090613bdf6001856142f6565b63ffffffff1663ffffffff1681526020019081526020016000206001015b90506000613c0a84613e95565b6001600160a01b03808616600090815260176020908152604080832063ffffffff861684528252808320938b1683526008909152902054845492935060019091019161040090613c5b9083906143d6565b1115613c795760405162461bcd60e51b8152600401610f0190614769565b60005b8454811015613ccb576000858281548110613c9957613c99614354565b600091825260208083209091015486546001810188558784529190922001555080613cc3816143ee565b915050613c7c565b5060005b81811015613d1d576001600160a01b0389166000908152600c602090815260408083208484528252822054855460018101875586845291909220015580613d15816143ee565b915050613ccf565b50613d29856001614741565b6001600160a01b0387166000908152601860205260409020805463ffffffff9290921663ffffffff199092169190911790555050505050505050565b60006001600160a01b038316613d7d57613d7d61436a565b613d8b6000612413856112bd565b613d958383613913565b60405182906001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a450600192915050565b6001600160a01b038216600090815260086020526040812054613dfb906001906143a2565b6000838152600d6020526040902054909150808203613e4a576001600160a01b0384166000908152600c602090815260408083208584528252808320839055858352600d909152812055611b9c565b6001600160a01b03939093166000908152600c6020908152604080832093835292815282822080548684528484208190558352600d9091528282209490945592839055908252812055565b6001600160a01b038116600090815260186020526040812054429063ffffffff168015801590613efe57506001600160a01b03841660009081526017602052604081208391613ee56001856142f6565b63ffffffff168152602081019190915260400160002054145b1561123a576113c36001826142f6565b6001600160e01b03198116811461130857600080fd5b600060208284031215613f3657600080fd5b813561123a81613f0e565b60005b83811015613f5c578181015183820152602001613f44565b83811115611b9c5750506000910152565b60008151808452613f85816020860160208601613f41565b601f01601f19169290920160200192915050565b60208152600061123a6020830184613f6d565b80356001600160a01b0381168114613fc357600080fd5b919050565b60008060408385031215613fdb57600080fd5b613fe483613fac565b946020939093013593505050565b60006020828403121561400457600080fd5b5035919050565b60006020828403121561401d57600080fd5b61123a82613fac565b6000806040838503121561403957600080fd5b50508035926020909101359150565b60008060006060848603121561405d57600080fd5b61406684613fac565b925061407460208501613fac565b9150604084013590509250925092565b801515811461130857600080fd5b600080604083850312156140a557600080fd5b6140ae83613fac565b915060208301356140be81614084565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614108576141086140c9565b604052919050565b600067ffffffffffffffff82111561412a5761412a6140c9565b50601f01601f191660200190565b6000806000806080858703121561414e57600080fd5b61415785613fac565b935061416560208601613fac565b925060408501359150606085013567ffffffffffffffff81111561418857600080fd5b8501601f8101871361419957600080fd5b80356141ac6141a782614110565b6140df565b8181528860208385010111156141c157600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060008060008060c087890312156141fc57600080fd5b61420587613fac565b95506020870135945060408701359350606087013560ff8116811461422957600080fd5b9598949750929560808101359460a0909101359350915050565b60008060006060848603121561425857600080fd5b833592506020840135915061426f60408501613fac565b90509250925092565b6000806040838503121561428b57600080fd5b61429483613fac565b91506142a260208401613fac565b90509250929050565b600080604083850312156142be57600080fd5b6142c783613fac565b9150602083013563ffffffff811681146140be57600080fd5b634e487b7160e01b600052601160045260246000fd5b600063ffffffff83811690831681811015614313576143136142e0565b039392505050565b634e487b7160e01b600052601260045260246000fd5b600063ffffffff808416806143485761434861431b565b92169190910492915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b602080825260089082015267185d1d1858da195960c21b604082015260600190565b6000828210156143b4576143b46142e0565b500390565b6000602082840312156143cb57600080fd5b815161123a81614084565b600082198211156143e9576143e96142e0565b500190565b600060018201614400576144006142e0565b5060010190565b6000816000190483118215151615614421576144216142e0565b500290565b6000826144355761443561431b565b500490565b60208082526024908201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686040820152636472617760e01b606082015260800190565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061157a90830184613f6d565b6000602082840312156144c357600080fd5b815161123a81613f0e565b6000602082840312156144e057600080fd5b815167ffffffffffffffff8111156144f757600080fd5b8201601f8101841361450857600080fd5b80516145166141a782614110565b81815285602083850101111561452b57600080fd5b612e5b826020830160208601613f41565b600081600f0b83600f0b806145535761455361431b565b60016001607f1b0319821460001982141615614571576145716142e0565b90059392505050565b600081600f0b83600f0b60016001607f1b036000821360008413838304851182821616156145aa576145aa6142e0565b60016001607f1b031960008512828116878305871216156145cd576145cd6142e0565b600087129250858205871284841616156145e9576145e96142e0565b858505871281841616156145ff576145ff6142e0565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b03190183128115161561463a5761463a6142e0565b8160016001607f1b03018313811615614655576146556142e0565b5090039392505050565b600081600f0b83600f0b600082128260016001607f1b0303821381151615614689576146896142e0565b8260016001607f1b03190382128116156146a5576146a56142e0565b50019392505050565b60008083128015600160ff1b8501841216156146cc576146cc6142e0565b6001600160ff1b03840183138116156146e7576146e76142e0565b50500390565b634e487b7160e01b600052602160045260246000fd5b84815260208101849052608081016005841061472f57634e487b7160e01b600052602160045260246000fd5b60408201939093526060015292915050565b600063ffffffff808316818516808303821115614760576147606142e0565b01949350505050565b60208082526023908201527f64737452657020776f756c64206861766520746f6f206d616e7920746f6b656e60408201526249647360e81b60608201526080019056fea2646970667358221220536afad48d87d79f11e5d3fc4a9bd0a225d7d0ec8ed2f78d750d0312fa7a332b64736f6c634300080d0033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef0000000000000000000000003c8b650257cfb5f272f799f5e2b4e65093a11a050000000000000000000000005f2f6721ca0c5ac522bc875fa3f09bf693dcfa1d

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106104075760003560e01c80637116c60c11610220578063c1f0fb9f11610130578063e7a324dc116100b8578063f1127ed811610087578063f1127ed814610abc578063f8a0576314610ae7578063fbd3a29d14610b0a578063fc0c546a14610b1d578063fd4a77f114610b4457600080fd5b8063e7a324dc14610a33578063e7e242d414610a5a578063e985e9c514610a6d578063ee99fe2814610aa957600080fd5b8063d1c2babb116100ff578063d1c2babb1461099c578063d1febfb9146109af578063d4e54c3b146109ed578063e0514aba14610a00578063e441135c14610a1357600080fd5b8063c1f0fb9f1461095b578063c2c4c5c11461096e578063c3cda52014610976578063c87b56dd1461098957600080fd5b806395d89b41116101b3578063a183af5211610182578063a183af52146108c7578063a22cb465146108da578063a4d855df146108ed578063b45a3c0e14610900578063b88d4fde1461094857600080fd5b806395d89b4114610465578063981b24d01461088e578063986b7d8a146108a15780639ab24eb0146108b457600080fd5b80638c2c9baf116101ef5780638c2c9baf1461083c5780638e539e8c1461084f5780638fbb38ff14610862578063900cf0cf1461088557600080fd5b80637116c60c146107d357806371197484146107e65780637ecebe001461080957806385f2aef21461082957600080fd5b8063313ce5671161031b5780635594a045116102ae5780636352211e1161027d5780636352211e1461073e57806365fc3873146107675780636f5488371461077a5780636fcfff451461079a57806370a08231146107c057600080fd5b80635594a045146106fc578063587cde1e1461070f5780635c19a95c146107225780635f5b0c321461073557600080fd5b8063461f711c116102ea578063461f711c1461068c57806346c96aac146106b25780634bc2a657146106c557806354fd4d50146106d857600080fd5b8063313ce567146106395780633a46b1a81461065357806342842e0e14610666578063430c20811461067957600080fd5b80631376f3da1161039e57806323b872dd1161036d57806323b872dd146105c457806325a58b56146105d75780632e1a7d4d146105dd5780632e720f7d146105f05780632f745c591461060357600080fd5b80631376f3da1461054757806318160ddd146105825780631c984bc31461058a57806320606b701461059d57600080fd5b8063081812fc116103da578063081812fc146104be578063095cf5c6146104ff578063095ea7b3146105145780630d6a20331461052757600080fd5b806301ffc9a71461040c578063047fc9aa1461044e57806306fdde03146104655780630758c7d814610496575b600080fd5b61043961041a366004613f24565b6001600160e01b03191660009081526004602052604090205460ff1690565b60405190151581526020015b60405180910390f35b61045760135481565b604051908152602001610445565b610489604051806040016040528060058152602001641d9953919560da1b81525081565b6040516104459190613f99565b6104a96104a4366004613fc8565b610b57565b60405163ffffffff9091168152602001610445565b6104e76104cc366004613ff2565b6000908152600960205260409020546001600160a01b031690565b6040516001600160a01b039091168152602001610445565b61051261050d36600461400b565b610cca565b005b610512610522366004613fc8565b610d03565b610457610535366004613ff2565b60146020526000908152604090205481565b61055a610555366004614026565b610deb565b60408051600f95860b81529390940b6020840152928201526060810191909152608001610445565b610457610e32565b610457610598366004614026565b610e42565b6104577f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6105126105d2366004614048565b610e74565b43610457565b6105126105eb366004613ff2565b610e85565b6105126105fe36600461400b565b61113b565b610457610611366004613fc8565b6001600160a01b03919091166000908152600c60209081526040808320938352929052205490565b610641601281565b60405160ff9091168152602001610445565b610457610661366004613fc8565b611174565b610512610674366004614048565b611213565b610439610687366004613fc8565b61122e565b61069f61069a366004613ff2565b611241565b604051600f9190910b8152602001610445565b6000546104e7906001600160a01b031681565b6105126106d336600461400b565b611284565b610489604051806040016040528060058152602001640312e302e360dc1b81525081565b6002546104e7906001600160a01b031681565b6104e761071d36600461400b565b6112bd565b61051261073036600461400b565b6112ed565b61045761040081565b6104e761074c366004613ff2565b6000908152600760205260409020546001600160a01b031690565b610457610775366004614026565b61130b565b610457610788366004613ff2565b600b6020526000908152604090205481565b6104a96107a836600461400b565b60186020526000908152604090205463ffffffff1681565b6104576107ce36600461400b565b61134d565b6104576107e1366004613ff2565b61136b565b61069f6107f4366004613ff2565b601260205260009081526040902054600f0b81565b61045761081736600461400b565b60196020526000908152604090205481565b6001546104e7906001600160a01b031681565b61045761084a366004614026565b6113cb565b61045761085d366004613ff2565b6113d7565b610439610870366004613ff2565b60156020526000908152604090205460ff1681565b61045760115481565b61045761089c366004613ff2565b6113e2565b6105126108af366004613ff2565b611584565b6104576108c236600461400b565b6115c8565b6105126108d5366004614026565b61169b565b6105126108e8366004614092565b61179a565b6105126108fb366004614026565b61181e565b61092e61090e366004613ff2565b60106020526000908152604090208054600190910154600f9190910b9082565b60408051600f9390930b8352602083019190915201610445565b610512610956366004614138565b611a03565b610512610969366004613ff2565b611ba2565b610512611bd1565b6105126109843660046141e3565b611c11565b610489610997366004613ff2565b611f51565b6105126109aa366004614026565b61207d565b61055a6109bd366004613ff2565b600360205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b6104576109fb366004614243565b6121e2565b610457610a0e366004614026565b612225565b610457610a21366004613ff2565b600e6020526000908152604090205481565b6104577fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b610457610a68366004613ff2565b612231565b610439610a7b366004614278565b6001600160a01b039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b610512610ab7366004614026565b612259565b610457610aca3660046142ab565b601760209081526000928352604080842090915290825290205481565b610457610af5366004613ff2565b60009081526010602052604090206001015490565b610512610b18366004613ff2565b61232d565b6104e77f0000000000000000000000003c8b650257cfb5f272f799f5e2b4e65093a11a0581565b610512610b52366004613ff2565b61235e565b6001600160a01b03821660009081526018602052604081205463ffffffff16808203610b87576000915050610cc4565b6001600160a01b03841660009081526017602052604081208491610bac6001856142f6565b63ffffffff16815260208101919091526040016000205411610bdb57610bd36001826142f6565b915050610cc4565b6001600160a01b0384166000908152601760209081526040808320838052909152902054831015610c10576000915050610cc4565b600080610c1e6001846142f6565b90505b8163ffffffff168163ffffffff161115610cbf5760006002610c4384846142f6565b610c4d9190614331565b610c5790836142f6565b6001600160a01b038816600090815260176020908152604080832063ffffffff851684529091529020805491925090879003610c9957509350610cc492505050565b8054871115610caa57819350610cb8565b610cb56001836142f6565b92505b5050610c21565b509150505b92915050565b6001546001600160a01b03163314610ce157600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600760205260409020546001600160a01b031680610d2557600080fd5b806001600160a01b0316836001600160a01b031603610d4357600080fd5b6000828152600760209081526040808320546001600160a01b038581168552600a845282852033808752945291909320549216149060ff168180610d845750805b610d8d57600080fd5b60008481526009602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918716917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a45050505050565b600f60205281600052604060002081633b9aca008110610e0a57600080fd5b6003020180546001820154600290920154600f82810b9550600160801b90920490910b925084565b6000610e3d4261136b565b905090565b6000828152600f6020526040812082633b9aca008110610e6457610e64614354565b6003020160010154905092915050565b610e8083838333612390565b505050565b60065460ff16600114610e9757600080fd5b6006805460ff19166002179055610eae3382612471565b610eba57610eba61436a565b600081815260146020526040902054158015610ee5575060008181526015602052604090205460ff16155b610f0a5760405162461bcd60e51b8152600401610f0190614380565b60405180910390fd5b60008181526010602090815260409182902082518084019093528054600f0b835260010154908201819052421015610f7d5760405162461bcd60e51b8152602060048201526016602482015275546865206c6f636b206469646e27742065787069726560501b6044820152606401610f01565b8051604080518082018252600080825260208083018281528783526010909152929020905181546001600160801b0319166001600160801b039091161781559051600190910155601354600f9190910b90610fd882826143a2565b6013556040805180820190915260008082526020820152610ffc90859085906124d7565b60405163a9059cbb60e01b8152336004820152602481018390527f0000000000000000000000003c8b650257cfb5f272f799f5e2b4e65093a11a056001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611069573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108d91906143b9565b6110995761109961436a565b6110a284612af3565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c8161111084826143a2565b6040805192835260208301919091520160405180910390a150506006805460ff191660011790555050565b6001546001600160a01b0316331461115257600080fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000806111818484610b57565b6001600160a01b038516600090815260176020908152604080832063ffffffff851684529091528120919250600190910190805b82548110156112095760008382815481106111d2576111d2614354565b906000526020600020015490506111e98188612bc6565b6111f390846143d6565b9250508080611201906143ee565b9150506111b5565b5095945050505050565b610e8083838360405180602001604052806000815250611a03565b600061123a8383612471565b9392505050565b6000818152600e6020908152604080832054600f909252822081633b9aca00811061126e5761126e614354565b6003020154600160801b9004600f0b9392505050565b6000546001600160a01b0316331461129b57600080fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0380821660009081526016602052604081205490911680156112e6578061123a565b5090919050565b6001600160a01b0381166112fe5750335b6113083382612c9a565b50565b60065460009060ff1660011461132057600080fd5b6006805460ff19166002179055611338838333612d0d565b90506006805460ff1916600117905592915050565b6001600160a01b038116600090815260086020526040812054610cc4565b601154600081815260036020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529091906113c38185612e64565b949350505050565b600061123a8383612f65565b6000610cc48261136b565b6000438211156113f4576113f461436a565b6011546000611403848361323e565b600081815260036020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152919250838310156115125760006003816114668660016143d6565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608083018290528501519192501461150c57826060015181606001516114d291906143a2565b836040015182604001516114e691906143a2565b60608501516114f5908a6143a2565b6114ff9190614407565b6115099190614426565b91505b50611561565b4382606001511461156157606082015161152c90436143a2565b604083015161153b90426143a2565b606084015161154a90896143a2565b6115549190614407565b61155e9190614426565b90505b61157a8282846040015161157591906143d6565b612e64565b9695505050505050565b6000546001600160a01b0316331461159b57600080fd5b6000818152601460205260409020546115b6906001906143a2565b60009182526014602052604090912055565b6001600160a01b03811660009081526018602052604081205463ffffffff168082036115f75750600092915050565b6001600160a01b03831660009081526017602052604081208161161b6001856142f6565b63ffffffff1663ffffffff16815260200190815260200160002060010190506000805b825481101561169257600083828154811061165b5761165b614354565b906000526020600020015490506116728142612bc6565b61167c90846143d6565b925050808061168a906143ee565b91505061163e565b50949350505050565b60065460ff166001146116ad57600080fd5b6006805460ff191660021790556116c43383612471565b6116d0576116d061436a565b60008281526010602090815260409182902082518084019093528054600f0b83526001015490820152816117065761170661436a565b60008160000151600f0b136117565760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401610f01565b428160200151116117795760405162461bcd60e51b8152600401610f019061443a565b611788838360008460026132c4565b50506006805460ff1916600117905550565b336001600160a01b038316036117b2576117b261436a565b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60065460ff1660011461183057600080fd5b6006805460ff191660021790556118473383612471565b6118535761185361436a565b600082815260106020908152604080832081518083019092528054600f0b825260010154918101919091529062093a808061188e85426143d6565b6118989190614426565b6118a29190614407565b9050428260200151116118e65760405162461bcd60e51b815260206004820152600c60248201526b131bd8dac8195e1c1a5c995960a21b6044820152606401610f01565b60008260000151600f0b136119315760405162461bcd60e51b8152602060048201526011602482015270139bdd1a1a5b99c81a5cc81b1bd8dad959607a1b6044820152606401610f01565b816020015181116119845760405162461bcd60e51b815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606401610f01565b611992630784ce00426143d6565b8111156119e15760405162461bcd60e51b815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006044820152606401610f01565b6119f0846000838560036132c4565b50506006805460ff191660011790555050565b611a0f84848433612390565b823b15611b9c57604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290611a4890339088908790879060040161447e565b6020604051808303816000875af1925050508015611a83575060408051601f3d908101601f19168201909252611a80918101906144b1565b60015b611b2b573d808015611ab1576040519150601f19603f3d011682016040523d82523d6000602084013e611ab6565b606091505b508051600003611b235760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610f01565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14611b9a5760405162461bcd60e51b815260206004820152602660248201527f4552433732313a2045524337323152656365697665722072656a656374656420604482015265746f6b656e7360d01b6064820152608401610f01565b505b50505050565b6000546001600160a01b03163314611bb957600080fd5b6000908152601560205260409020805460ff19169055565b611c0f600060405180604001604052806000600f0b8152602001600081525060405180604001604052806000600f0b815260200160008152506124d7565b565b6040805180820182526005808252641d9953919560da1b60209283015282518084018452908152640312e302e360dc1b9082015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fc792e9874e7b42c234d1e8448cec020a0f065019c8cd6f7ccdb65b8c110157e9818401527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c60608201524660808201523060a0808301919091528351808303909101815260c0820184528051908301207fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60e08301526001600160a01b038a1661010083015261012082018990526101408083018990528451808403909101815261016083019094528351939092019290922061190160f01b61018084015261018283018290526101a2830181905290916000906101c20160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa158015611dd0573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611e4a5760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e7660448201526d616c6964207369676e617475726560901b6064820152608401610f01565b6001600160a01b0381166000908152601960205260408120805491611e6e836143ee565b919050558914611ed35760405162461bcd60e51b815260206004820152602a60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a20696e76604482015269616c6964206e6f6e636560b01b6064820152608401610f01565b87421115611f3a5760405162461bcd60e51b815260206004820152602e60248201527f566f74696e67457363726f773a3a64656c656761746542795369673a2073696760448201526d1b985d1d5c9948195e1c1a5c995960921b6064820152608401610f01565b611f44818b612c9a565b505050505b505050505050565b6000818152600760205260409020546060906001600160a01b0316611fb85760405162461bcd60e51b815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606401610f01565b60008281526010602090815260409182902082518084019093528054600f0b835260010154908201526002546001600160a01b031663dd9ec14984611ffd8142612bc6565b6020850151855160405160e086901b6001600160e01b0319168152600481019490945260248401929092526044830152600f0b6064820152608401600060405180830381865afa158015612055573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261123a91908101906144ce565b6000828152601460205260409020541580156120a8575060008281526015602052604090205460ff16155b6120c45760405162461bcd60e51b8152600401610f0190614380565b8082036120d057600080fd5b6120da3383612471565b6120e357600080fd5b6120ed3382612471565b6120f657600080fd5b6000828152601060208181526040808420815180830183528154600f90810b825260019283015482860190815288885295855283872084518086019095528054820b855290920154938301849052805194519095929490910b921115612160578260200151612166565b83602001515b604080518082018252600080825260208083018281528b835260108252848320935184546001600160801b0319166001600160801b03909116178455516001909301929092558251808401909352808352908201529091506121cb90879086906124d7565b6121d486612af3565b611f498583838660046132c4565b60065460009060ff166001146121f757600080fd5b6006805460ff1916600217905561220f848484612d0d565b90506006805460ff191660011790559392505050565b600061123a8383612bc6565b6000818152600b602052604081205443900361224f57506000919050565b610cc48242612bc6565b60065460ff1660011461226b57600080fd5b6006805460ff1916600217905560008281526010602090815260409182902082518084019093528054600f0b83526001015490820152816122ab57600080fd5b60008160000151600f0b136122fb5760405162461bcd60e51b8152602060048201526016602482015275139bc8195e1a5cdd1a5b99c81b1bd8dac8199bdd5b9960521b6044820152606401610f01565b4281602001511161231e5760405162461bcd60e51b8152600401610f019061443a565b611788838360008460006132c4565b6000546001600160a01b0316331461234457600080fd5b6000818152601460205260409020546115b69060016143d6565b6000546001600160a01b0316331461237557600080fd5b6000908152601560205260409020805460ff19166001179055565b6000828152601460205260409020541580156123bb575060008281526015602052604090205460ff16155b6123d75760405162461bcd60e51b8152600401610f0190614380565b6123e18183612471565b6123ea57600080fd5b6123f484836134c9565b6123fe8483613530565b61241961240a856112bd565b612413856112bd565b846135b1565b6124238383613913565b6000828152600b60205260408082204390555183916001600160a01b0380871692908816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050565b60008181526007602090815260408083205460098352818420546001600160a01b03918216808652600a855283862088841680885295529285205492938085149392909116149060ff1682806124c45750815b806124cc5750805b979650505050505050565b6040805160808101825260008082526020820181905291810182905260608101919091526040805160808101825260008082526020820181905291810182905260608101919091526011546000908190871561264257428760200151118015612547575060008760000151600f0b135b1561258c57865161255d90630784ce009061453c565b600f0b6020808701919091528701516125779042906143a2565b8560200151612586919061457a565b600f0b85525b4286602001511180156125a6575060008660000151600f0b135b156125eb5785516125bc90630784ce009061453c565b600f0b6020808601919091528601516125d69042906143a2565b84602001516125e5919061457a565b600f0b84525b602080880151600090815260128252604090205490870151600f9190910b93501561264257866020015186602001510361262757829150612642565b602080870151600090815260129091526040902054600f0b91505b6040805160808101825260008082526020820152429181019190915243606082015281156126b7575060008181526003602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b6040810151816000428310156127045760408401516126d690426143a2565b60608501516126e590436143a2565b6126f790670de0b6b3a7640000614407565b6127019190614426565b90505b600062093a806127148186614426565b61271e9190614407565b905060005b60ff8110156128985761273962093a80836143d6565b915060004283111561274d57429250612761565b50600082815260126020526040902054600f0b5b61276b86846143a2565b876020015161277a919061457a565b8751889061278990839061460f565b600f0b9052506020870180518291906127a390839061465f565b600f90810b90915288516000910b121590506127be57600087525b60008760200151600f0b12156127d657600060208801525b60408088018490528501519295508592670de0b6b3a7640000906127fa90856143a2565b6128049086614407565b61280e9190614426565b856060015161281d91906143d6565b606088015261282d6001896143d6565b97504283036128425750436060870152612898565b6000888152600360209081526040918290208951918a01516001600160801b03908116600160801b029216919091178155908801516001820155606088015160029091015550612891816143ee565b9050612723565b505060118590558b1561292357886020015188602001516128b9919061460f565b846020018181516128ca919061465f565b600f0b905250885188516128de919061460f565b845185906128ed90839061465f565b600f90810b90915260208601516000910b1215905061290e57600060208501525b60008460000151600f0b121561292357600084525b6000858152600360209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101558b15612ae557428b6020015111156129da576020890151612989908861465f565b96508a602001518a60200151036129ac5760208801516129a9908861460f565b96505b60208b810151600090815260129091526040902080546001600160801b0319166001600160801b0389161790555b428a602001511115612a35578a602001518a602001511115612a35576020880151612a05908761460f565b60208b810151600090815260129091526040902080546001600160801b0319166001600160801b03831617905595505b60008c8152600e6020526040812054612a4f9060016143d6565b905080600e60008f815260200190815260200160002081905550428960400181815250504389606001818152505088600f60008f815260200190815260200160002082633b9aca008110612aa557612aa5614354565b825160208401516001600160801b03908116600160801b029116176003919091029190910190815560408201516001820155606090910151600290910155505b505050505050505050505050565b612afd3382612471565b612b495760405162461bcd60e51b815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665646044820152606401610f01565b6000818152600760205260408120546001600160a01b031690612b6c9083610d03565b612b80612b78826112bd565b6000846135b1565b612b8a3383613530565b60405182906000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000828152600e6020526040812054808203612be6576000915050610cc4565b6000848152600f6020526040812082633b9aca008110612c0857612c08614354565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b602083015260018101549282018390526002015460608201529150612c5490856146ae565b8160200151612c63919061457a565b81518290612c7290839061460f565b600f90810b90915282516000910b12159050612c8d57600081525b51600f0b9150610cc49050565b6000612ca5836112bd565b6001600160a01b0384811660008181526016602052604080822080546001600160a01b031916888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4610e808382846139a9565b60008062093a8080612d1f86426143d6565b612d299190614426565b612d339190614407565b905060008511612d4257600080fd5b428111612da05760405162461bcd60e51b815260206004820152602660248201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060448201526566757475726560d01b6064820152608401610f01565b612dae630784ce00426143d6565b811115612dfd5760405162461bcd60e51b815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006044820152606401610f01565b600560008154612e0c906143ee565b90915550600554612e1d8482613d65565b5060008181526010602090815260409182902082518084019093528054600f0b835260019081015491830191909152612e5b918391899186916132c4565b95945050505050565b600080839050600062093a80808360400151612e809190614426565b612e8a9190614407565b905060005b60ff811015612f3d57612ea562093a80836143d6565b9150600085831115612eb957859250612ecd565b50600082815260126020526040902054600f0b5b6040840151612edc90846143a2565b8460200151612eeb919061457a565b84518590612efa90839061460f565b600f0b905250858303612f0d5750612f3d565b8084602001818151612f1f919061465f565b600f0b9052505060408301829052612f36816143ee565b9050612e8f565b5060008260000151600f0b1215612f5357600082525b50516001600160801b03169392505050565b600043821115612f7757612f7761436a565b6000838152600e6020526040812054815b608081101561301757818310156130175760006002612fa784866143d6565b612fb29060016143d6565b612fbc9190614426565b6000888152600f60205260409020909150869082633b9aca008110612fe357612fe3614354565b600302016002015411612ff857809350613006565b6130036001826143a2565b92505b50613010816143ee565b9050612f88565b506000858152600f6020526040812083633b9aca00811061303a5761303a614354565b60408051608081018252600392909202929092018054600f81810b8452600160801b909104900b60208301526001810154928201929092526002909101546060820152601154909150600061308f878361323e565b600081815260036020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152919250808484101561316e5760006003816130f38760016143d6565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606080830182905286015191925061315091906143a2565b92508360400151816040015161316691906143a2565b915050613192565b606083015161317d90436143a2565b915082604001514261318f91906143a2565b90505b604083015182156131cf578284606001518c6131ae91906143a2565b6131b89084614407565b6131c29190614426565b6131cc90826143d6565b90505b60408701516131de90826143a2565b87602001516131ed919061457a565b875188906131fc90839061460f565b600f90810b90915288516000910b12905061322c57505093516001600160801b03169650610cc495505050505050565b60009950505050505050505050610cc4565b60008082815b60808110156132ba57818310156132ba576000600261326384866143d6565b61326e9060016143d6565b6132789190614426565b600081815260036020526040902060020154909150871061329b578093506132a9565b6132a66001826143a2565b92505b506132b3816143ee565b9050613244565b5090949350505050565b60135482906132d386826143d6565b6013556040805180820190915260008082526020820152825160208085015190830152600f0b815282518790849061330c90839061465f565b600f0b905250851561332057602083018690525b6000888152601060209081526040909120845181546001600160801b0319166001600160801b03909116178155908401516001909101556133628882856124d7565b33871580159061338457506004856004811115613381576133816146ed565b14155b1561342e576040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018a90527f0000000000000000000000003c8b650257cfb5f272f799f5e2b4e65093a11a0516906323b872dd906064016020604051808303816000875af11580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061342291906143b9565b61342e5761342e61436a565b8360200151816001600160a01b03167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248b8b89426040516134729493929190614703565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c836134a68a826143d6565b6040805192835260208301919091520160405180910390a1505050505050505050565b6000818152600760205260409020546001600160a01b038381169116146134f2576134f261436a565b6000818152600960205260409020546001600160a01b03161561352c57600081815260096020526040902080546001600160a01b03191690555b5050565b6000818152600760205260409020546001600160a01b038381169116146135595761355961436a565b600081815260076020526040902080546001600160a01b031916905561357f8282613dd6565b6001600160a01b03821660009081526008602052604081208054600192906135a89084906143a2565b90915550505050565b816001600160a01b0316836001600160a01b0316141580156135d35750600081115b15610e80576001600160a01b03831615613754576001600160a01b03831660009081526018602052604081205463ffffffff169081613637576001600160a01b03851660009081526017602090815260408083208380529091529020600101613679565b6001600160a01b03851660009081526017602052604081209061365b6001856142f6565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061368686613e95565b6001600160a01b038716600090815260176020908152604080832063ffffffff8516845290915281209192506001909101905b83548110156137135760008482815481106136d6576136d6614354565b90600052602060002001549050868114613700578254600181018455600084815260209020018190555b508061370b816143ee565b9150506136b9565b5061371f846001614741565b6001600160a01b0388166000908152601860205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03821615610e80576001600160a01b03821660009081526018602052604081205463ffffffff1690816137b3576001600160a01b038416600090815260176020908152604080832083805290915290206001016137f5565b6001600160a01b0384166000908152601760205260408120906137d76001856142f6565b63ffffffff1663ffffffff1681526020019081526020016000206001015b9050600061380285613e95565b6001600160a01b038616600090815260176020908152604080832063ffffffff85168452909152902083549192506001908101916104009161384491906143d6565b11156138625760405162461bcd60e51b8152600401610f0190614769565b60005b83548110156138b457600084828154811061388257613882614354565b6000918252602080832090910154855460018101875586845291909220015550806138ac816143ee565b915050613865565b508054600181810183556000838152602090209091018690556138d8908590614741565b6001600160a01b0387166000908152601860205260409020805463ffffffff9290921663ffffffff1990921691909117905550505050505050565b6000818152600760205260409020546001600160a01b0316156139385761393861436a565b600081815260076020908152604080832080546001600160a01b0319166001600160a01b03871690811790915580845260088084528285208054600c86528487208188528652848720889055878752600d8652938620939093559084529091528054600192906135a89084906143d6565b806001600160a01b0316826001600160a01b031614610e80576001600160a01b03821615613b5c576001600160a01b03821660009081526018602052604081205463ffffffff169081613a21576001600160a01b03841660009081526017602090815260408083208380529091529020600101613a63565b6001600160a01b038416600090815260176020526040812090613a456001856142f6565b63ffffffff1663ffffffff1681526020019081526020016000206001015b90506000613a7085613e95565b6001600160a01b038616600090815260176020908152604080832063ffffffff8516845290915281209192506001909101905b8354811015613b1b576000848281548110613ac057613ac0614354565b600091825260208083209091015480835260079091526040909120549091506001600160a01b03908116908a1614613b08578254600181018455600084815260209020018190555b5080613b13816143ee565b915050613aa3565b50613b27846001614741565b6001600160a01b0387166000908152601860205260409020805463ffffffff191663ffffffff92909216919091179055505050505b6001600160a01b03811615610e80576001600160a01b03811660009081526018602052604081205463ffffffff169081613bbb576001600160a01b03831660009081526017602090815260408083208380529091529020600101613bfd565b6001600160a01b038316600090815260176020526040812090613bdf6001856142f6565b63ffffffff1663ffffffff1681526020019081526020016000206001015b90506000613c0a84613e95565b6001600160a01b03808616600090815260176020908152604080832063ffffffff861684528252808320938b1683526008909152902054845492935060019091019161040090613c5b9083906143d6565b1115613c795760405162461bcd60e51b8152600401610f0190614769565b60005b8454811015613ccb576000858281548110613c9957613c99614354565b600091825260208083209091015486546001810188558784529190922001555080613cc3816143ee565b915050613c7c565b5060005b81811015613d1d576001600160a01b0389166000908152600c602090815260408083208484528252822054855460018101875586845291909220015580613d15816143ee565b915050613ccf565b50613d29856001614741565b6001600160a01b0387166000908152601860205260409020805463ffffffff9290921663ffffffff199092169190911790555050505050505050565b60006001600160a01b038316613d7d57613d7d61436a565b613d8b6000612413856112bd565b613d958383613913565b60405182906001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a450600192915050565b6001600160a01b038216600090815260086020526040812054613dfb906001906143a2565b6000838152600d6020526040902054909150808203613e4a576001600160a01b0384166000908152600c602090815260408083208584528252808320839055858352600d909152812055611b9c565b6001600160a01b03939093166000908152600c6020908152604080832093835292815282822080548684528484208190558352600d9091528282209490945592839055908252812055565b6001600160a01b038116600090815260186020526040812054429063ffffffff168015801590613efe57506001600160a01b03841660009081526017602052604081208391613ee56001856142f6565b63ffffffff168152602081019190915260400160002054145b1561123a576113c36001826142f6565b6001600160e01b03198116811461130857600080fd5b600060208284031215613f3657600080fd5b813561123a81613f0e565b60005b83811015613f5c578181015183820152602001613f44565b83811115611b9c5750506000910152565b60008151808452613f85816020860160208601613f41565b601f01601f19169290920160200192915050565b60208152600061123a6020830184613f6d565b80356001600160a01b0381168114613fc357600080fd5b919050565b60008060408385031215613fdb57600080fd5b613fe483613fac565b946020939093013593505050565b60006020828403121561400457600080fd5b5035919050565b60006020828403121561401d57600080fd5b61123a82613fac565b6000806040838503121561403957600080fd5b50508035926020909101359150565b60008060006060848603121561405d57600080fd5b61406684613fac565b925061407460208501613fac565b9150604084013590509250925092565b801515811461130857600080fd5b600080604083850312156140a557600080fd5b6140ae83613fac565b915060208301356140be81614084565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614108576141086140c9565b604052919050565b600067ffffffffffffffff82111561412a5761412a6140c9565b50601f01601f191660200190565b6000806000806080858703121561414e57600080fd5b61415785613fac565b935061416560208601613fac565b925060408501359150606085013567ffffffffffffffff81111561418857600080fd5b8501601f8101871361419957600080fd5b80356141ac6141a782614110565b6140df565b8181528860208385010111156141c157600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060008060008060c087890312156141fc57600080fd5b61420587613fac565b95506020870135945060408701359350606087013560ff8116811461422957600080fd5b9598949750929560808101359460a0909101359350915050565b60008060006060848603121561425857600080fd5b833592506020840135915061426f60408501613fac565b90509250925092565b6000806040838503121561428b57600080fd5b61429483613fac565b91506142a260208401613fac565b90509250929050565b600080604083850312156142be57600080fd5b6142c783613fac565b9150602083013563ffffffff811681146140be57600080fd5b634e487b7160e01b600052601160045260246000fd5b600063ffffffff83811690831681811015614313576143136142e0565b039392505050565b634e487b7160e01b600052601260045260246000fd5b600063ffffffff808416806143485761434861431b565b92169190910492915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b602080825260089082015267185d1d1858da195960c21b604082015260600190565b6000828210156143b4576143b46142e0565b500390565b6000602082840312156143cb57600080fd5b815161123a81614084565b600082198211156143e9576143e96142e0565b500190565b600060018201614400576144006142e0565b5060010190565b6000816000190483118215151615614421576144216142e0565b500290565b6000826144355761443561431b565b500490565b60208082526024908201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686040820152636472617760e01b606082015260800190565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061157a90830184613f6d565b6000602082840312156144c357600080fd5b815161123a81613f0e565b6000602082840312156144e057600080fd5b815167ffffffffffffffff8111156144f757600080fd5b8201601f8101841361450857600080fd5b80516145166141a782614110565b81815285602083850101111561452b57600080fd5b612e5b826020830160208601613f41565b600081600f0b83600f0b806145535761455361431b565b60016001607f1b0319821460001982141615614571576145716142e0565b90059392505050565b600081600f0b83600f0b60016001607f1b036000821360008413838304851182821616156145aa576145aa6142e0565b60016001607f1b031960008512828116878305871216156145cd576145cd6142e0565b600087129250858205871284841616156145e9576145e96142e0565b858505871281841616156145ff576145ff6142e0565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b03190183128115161561463a5761463a6142e0565b8160016001607f1b03018313811615614655576146556142e0565b5090039392505050565b600081600f0b83600f0b600082128260016001607f1b0303821381151615614689576146896142e0565b8260016001607f1b03190382128116156146a5576146a56142e0565b50019392505050565b60008083128015600160ff1b8501841216156146cc576146cc6142e0565b6001600160ff1b03840183138116156146e7576146e76142e0565b50500390565b634e487b7160e01b600052602160045260246000fd5b84815260208101849052608081016005841061472f57634e487b7160e01b600052602160045260246000fd5b60408201939093526060015292915050565b600063ffffffff808316818516808303821115614760576147606142e0565b01949350505050565b60208082526023908201527f64737452657020776f756c64206861766520746f6f206d616e7920746f6b656e60408201526249647360e81b60608201526080019056fea2646970667358221220536afad48d87d79f11e5d3fc4a9bd0a225d7d0ec8ed2f78d750d0312fa7a332b64736f6c634300080d0033

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

0000000000000000000000003c8b650257cfb5f272f799f5e2b4e65093a11a050000000000000000000000005f2f6721ca0c5ac522bc875fa3f09bf693dcfa1d

-----Decoded View---------------
Arg [0] : token_addr (address): 0x3c8B650257cFb5f272f799F5e2b4e65093a11a05
Arg [1] : art_proxy (address): 0x5F2f6721Ca0C5AC522BC875fA3F09bF693dcFa1D

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000003c8b650257cfb5f272f799f5e2b4e65093a11a05
Arg [1] : 0000000000000000000000005f2f6721ca0c5ac522bc875fa3f09bf693dcfa1d


Deployed Bytecode Sourcemap

13069:56061:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29338:136;;;;;;:::i;:::-;-1:-1:-1;;;;;;29433:33:0;29409:4;29433:33;;;:19;:33;;;;;;;;;29338:136;;;;565:14:1;;558:22;540:41;;528:2;513:18;29338:136:0;;;;;;;;34538:18;;;;;;;;;738:25:1;;;726:2;711:18;34538::0;592:177:1;16792:37:0;;;;;;;;;;;;;;;-1:-1:-1;;;16792:37:0;;;;;;;;;;;;:::i;60338:1064::-;;;;;;:::i;:::-;;:::i;:::-;;;2136:10:1;2124:23;;;2106:42;;2094:2;2079:18;60338:1064:0;1962:192:1;19757:117:0;;;;;;:::i;:::-;19816:7;19843:23;;;:13;:23;;;;;;-1:-1:-1;;;;;19843:23:0;;19757:117;;;;-1:-1:-1;;;;;2508:32:1;;;2490:51;;2478:2;2463:18;19757:117:0;2344:203:1;16973:110:0;;;;;;:::i;:::-;;:::i;:::-;;20978:658;;;;;;:::i;:::-;;:::i;56551:40::-;;;;;;:::i;:::-;;;;;;;;;;;;;;34285:60;;;;;;:::i;:::-;;:::i;:::-;;;;3252:2:1;3241:22;;;3223:41;;3300:22;;;;3295:2;3280:18;;3273:50;3339:18;;;3332:34;3397:2;3382:18;;3375:34;;;;3210:3;3195:19;34285:60:0;2996:419:1;55871:109:0;;;:::i;35532:150::-;;;;;;:::i;:::-;;:::i;58317:122::-;;58359:80;58317:122;;25746:174;;;;;;:::i;:::-;;:::i;43818:91::-;43889:12;43818:91;;48278:972;;;;;;:::i;:::-;;:::i;17091:120::-;;;;;;:::i;:::-;;:::i;29970:159::-;;;;;;:::i;:::-;-1:-1:-1;;;;;30080:28:0;;;;30056:4;30080:28;;;:20;:28;;;;;;;;:41;;;;;;;;;29970:159;16929:35;;16962:2;16929:35;;;;;4107:4:1;4095:17;;;4077:36;;4065:2;4050:18;16929:35:0;3935:184:1;61410:582:0;;;;;;:::i;:::-;;:::i;26651:173::-;;;;;;:::i;:::-;;:::i;23697:153::-;;;;;;:::i;:::-;;:::i;35131:194::-;;;;;;:::i;:::-;;:::i;:::-;;;4297:2:1;4286:22;;;;4268:41;;4256:2;4241:18;35131:194:0;4124:191:1;14642:20:0;;;;;-1:-1:-1;;;;;14642:20:0;;;56641:115;;;;;;:::i;:::-;;:::i;16882:40::-;;;;;;;;;;;;;;;-1:-1:-1;;;16882:40:0;;;;;14695:23;;;;;-1:-1:-1;;;;;14695:23:0;;;59443:187;;;;;;:::i;:::-;;:::i;67758:164::-;;;;;;:::i;:::-;;:::i;58764:41::-;;58801:4;58764:41;;18303:107;;;;;;:::i;:::-;18356:7;18383:19;;;:9;:19;;;;;;-1:-1:-1;;;;;18383:19:0;;18303:107;46013:166;;;;;;:::i;:::-;;:::i;19581:45::-;;;;;;:::i;:::-;;;;;;;;;;;;;;59057:48;;;;;;:::i;:::-;;;;;;;;;;;;;;;;19010:106;;;;;;:::i;:::-;;:::i;56154:198::-;;;;;;:::i;:::-;;:::i;34456:44::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;59186:38;;;;;;:::i;:::-;;;;;;;;;;;;;;14669:19;;;;;-1:-1:-1;;;;;14669:19:0;;;53601:140;;;;;;:::i;:::-;;:::i;62000:127::-;;;;;;:::i;:::-;;:::i;56598:34::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;34432:17;;;;;;53937:880;;;;;;:::i;:::-;;:::i;57177:147::-;;;;;;:::i;:::-;;:::i;59831:499::-;;;;;;:::i;:::-;;:::i;46803:503::-;;;;;;:::i;:::-;;:::i;22148:301::-;;;;;;:::i;:::-;;:::i;47442:724::-;;;;;;:::i;:::-;;:::i;34381:44::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4964:2:1;4953:22;;;;4935:41;;5007:2;4992:18;;4985:34;;;;4908:18;34381:44:0;4763:262:1;28033:998:0;;;;;;:::i;:::-;;:::i;56892:122::-;;;;;;:::i;:::-;;:::i;43967:106::-;;;:::i;67930:1197::-;;;;;;:::i;:::-;;:::i;17320:428::-;;;;;;:::i;:::-;;:::i;57332:722::-;;;;;;:::i;:::-;;:::i;14727:43::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;14727:43:0;;;;;;;;;46447:176;;;;;;:::i;:::-;;:::i;51463:130::-;;;;;;:::i;:::-;;:::i;34233:45::-;;;;;;:::i;:::-;;;;;;;;;;;;;;58533:117;;58579:71;58533:117;;51256:199;;;;;;:::i;:::-;;:::i;20083:153::-;;;;;;:::i;:::-;-1:-1:-1;;;;;20192:24:0;;;20167:4;20192:24;;;:16;:24;;;;;;;;20191:37;;;;;;;;;;;;;;;20083:153;44398:433;;;;;;:::i;:::-;;:::i;58920:68::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;35831:111;;;;;;:::i;:::-;35890:4;35914:16;;;:6;:16;;;;;:20;;;;35831:111;57022:147;;;;;;:::i;:::-;;:::i;14605:30::-;;;;;56764:120;;;;;;:::i;:::-;;:::i;60338:1064::-;-1:-1:-1;;;;;60460:23:0;;60419:6;60460:23;;;:14;:23;;;;;;;;60498:17;;;60494:58;;60539:1;60532:8;;;;;60494:58;-1:-1:-1;;;;;60610:20:0;;;;;;:11;:20;;;;;60662:9;;60631:16;60646:1;60631:12;:16;:::i;:::-;60610:38;;;;;;;;;;;;;-1:-1:-1;60610:38:0;:48;:61;60606:119;;60696:16;60711:1;60696:12;:16;:::i;:::-;60688:25;;;;;60606:119;-1:-1:-1;;;;;60786:20:0;;;;;;:11;:20;;;;;;;;:23;;;;;;;;:33;:45;-1:-1:-1;60782:86:0;;;60855:1;60848:8;;;;;60782:86;60880:12;;60922:16;60937:1;60922:12;:16;:::i;:::-;60907:31;;60949:423;60964:5;60956:13;;:5;:13;;;60949:423;;;60986:13;61028:1;61011:13;61019:5;61011;:13;:::i;:::-;61010:19;;;;:::i;:::-;61002:27;;:5;:27;:::i;:::-;-1:-1:-1;;;;;61095:20:0;;61071:21;61095:20;;;:11;:20;;;;;;;;:28;;;;;;;;;;61142:12;;60986:43;;-1:-1:-1;61095:28:0;61142:25;;;61138:223;;-1:-1:-1;61195:6:0;-1:-1:-1;61188:13:0;;-1:-1:-1;;;61188:13:0;61138:223;61227:12;;:24;-1:-1:-1;61223:138:0;;;61280:6;61272:14;;61223:138;;;61335:10;61344:1;61335:6;:10;:::i;:::-;61327:18;;61223:138;60971:401;;60949:423;;;-1:-1:-1;61389:5:0;-1:-1:-1;;60338:1064:0;;;;;:::o;16973:110::-;17047:4;;-1:-1:-1;;;;;17047:4:0;17033:10;:18;17025:27;;;;;;17063:4;:12;;-1:-1:-1;;;;;;17063:12:0;-1:-1:-1;;;;;17063:12:0;;;;;;;;;;16973:110::o;20978:658::-;21047:13;21063:19;;;:9;:19;;;;;;-1:-1:-1;;;;;21063:19:0;;21145:28;;;;;;21260:5;-1:-1:-1;;;;;21247:18:0;:9;-1:-1:-1;;;;;21247:18:0;;21239:27;;;;;;21308:18;21330:19;;;:9;:19;;;;;;;;;-1:-1:-1;;;;;21406:23:0;;;;;:16;:23;;;;;21353:10;21405:37;;;;;;;;;;21330:19;;:33;;21405:37;;21330:33;;21461:39;;;21478:22;21461:39;21453:48;;;;;;21541:23;;;;:13;:23;;;;;;:35;;-1:-1:-1;;;;;;21541:35:0;-1:-1:-1;;;;;21541:35:0;;;;;;;;;21592:36;;21541:23;;21592:36;;;;;;;21036:600;;;20978:658;;:::o;34285:60::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;34285:60:0;;;;;;;-1:-1:-1;34285:60:0;:::o;55871:109::-;55917:4;55941:31;55956:15;55941:14;:31::i;:::-;55934:38;;55871:109;:::o;35532:150::-;35613:4;35637:28;;;:18;:28;;;;;35666:4;35637:34;;;;;;;:::i;:::-;;;;:37;;;35630:44;;35532:150;;;;:::o;25746:174::-;25865:47;25879:5;25886:3;25891:8;25901:10;25865:13;:47::i;:::-;25746:174;;;:::o;48278:972::-;16467:14;;:30;:14;16333:1;16467:30;16459:39;;;;;;16509:14;:25;;-1:-1:-1;;16509:25:0;16376:1;16509:25;;;48351:40:::1;48370:10;48382:8:::0;48351:18:::1;:40::i;:::-;48344:48;;;;:::i;:::-;48411:21;::::0;;;:11:::1;:21;::::0;;;;;:26;:46;::::1;;;-1:-1:-1::0;48442:15:0::1;::::0;;;:5:::1;:15;::::0;;;;;::::1;;48441:16;48411:46;48403:67;;;;-1:-1:-1::0;;;48403:67:0::1;;;;;;;:::i;:::-;;;;;;;;;48483:28;48514:16:::0;;;:6:::1;:16;::::0;;;;;;;;48483:47;;;;::::1;::::0;;;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;;48549:15:::1;:30;;48541:65;;;::::0;-1:-1:-1;;;48541:65:0;;9584:2:1;48541:65:0::1;::::0;::::1;9566:21:1::0;9623:2;9603:18;;;9596:30;-1:-1:-1;;;9642:18:1;;;9635:52;9704:18;;48541:65:0::1;9382:346:1::0;48541:65:0::1;48642:14:::0;;48690:18:::1;::::0;;;;::::1;::::0;;-1:-1:-1;48690:18:0;;;::::1;::::0;;::::1;::::0;;;48671:16;;;:6:::1;:16:::0;;;;;;:37;;;;-1:-1:-1;;;;;;48671:37:0::1;-1:-1:-1::0;;;;;48671:37:0;;;::::1;::::0;;;;-1:-1:-1;48671:37:0;;::::1;::::0;48740:6:::1;::::0;48635:22:::1;::::0;;;::::1;::::0;48766:21:::1;48635:22:::0;48740:6;48766:21:::1;:::i;:::-;48757:6;:30:::0;48976:18:::1;::::0;;;;::::1;::::0;;;-1:-1:-1;48976:18:0;;;::::1;::::0;::::1;::::0;48945:50:::1;::::0;48957:8;;48967:7;;48945:11:::1;:50::i;:::-;49015:41;::::0;-1:-1:-1;;;49015:41:0;;49038:10:::1;49015:41;::::0;::::1;10037:51:1::0;10104:18;;;10097:34;;;49022:5:0::1;-1:-1:-1::0;;;;;49015:22:0::1;::::0;::::1;::::0;10010:18:1;;49015:41:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;49008:49;;;;:::i;:::-;49095:15;49101:8;49095:5;:15::i;:::-;49128:54;::::0;;10594:25:1;;;10650:2;10635:18;;10628:34;;;49166:15:0::1;10678:18:1::0;;;10671:34;49128:54:0;;49137:10:::1;::::0;49128:54:::1;::::0;;;;;10582:2:1;49128:54:0;;::::1;49198:44;49205:13:::0;49220:21:::1;49236:5:::0;49205:13;49220:21:::1;:::i;:::-;49198:44;::::0;;10890:25:1;;;10946:2;10931:18;;10924:34;;;;10863:18;49198:44:0::1;;;;;;;-1:-1:-1::0;;16557:14:0;:29;;-1:-1:-1;;16557:29:0;16333:1;16557:29;;;-1:-1:-1;;48278:972:0:o;17091:120::-;17170:4;;-1:-1:-1;;;;;17170:4:0;17156:10;:18;17148:27;;;;;;17186:8;:17;;-1:-1:-1;;;;;;17186:17:0;-1:-1:-1;;;;;17186:17:0;;;;;;;;;;17091:120::o;61410:582::-;61513:4;61535:18;61556:37;61574:7;61583:9;61556:17;:37::i;:::-;-1:-1:-1;;;;;61653:20:0;;61626:24;61653:20;;;:11;:20;;;;;;;;:33;;;;;;;;;;61535:58;;-1:-1:-1;61653:42:0;;;;;61626:24;61731:231;61752:16;;61748:20;;61731:231;;;61790:8;61801:9;61811:1;61801:12;;;;;;;;:::i;:::-;;;;;;;;;61790:23;;61921:29;61935:3;61940:9;61921:13;:29::i;:::-;61913:37;;:5;:37;:::i;:::-;61905:45;;61775:187;61770:3;;;;;:::i;:::-;;;;61731:231;;;-1:-1:-1;61979:5:0;61410:582;-1:-1:-1;;;;;61410:582:0:o;26651:173::-;26774:42;26791:5;26798:3;26803:8;26774:42;;;;;;;;;;;;:16;:42::i;23697:153::-;23780:4;23804:38;23823:8;23833;23804:18;:38::i;:::-;23797:45;23697:153;-1:-1:-1;;;23697:153:0:o;35131:194::-;35198:6;35231:26;;;:16;:26;;;;;;;;;35275:18;:28;;;;;35231:26;35275:36;;;;;;;:::i;:::-;;;;:42;-1:-1:-1;;;35275:42:0;;;;;35131:194;-1:-1:-1;;;35131:194:0:o;56641:115::-;56717:5;;-1:-1:-1;;;;;56717:5:0;56703:10;:19;56695:28;;;;;;56734:5;:14;;-1:-1:-1;;;;;;56734:14:0;-1:-1:-1;;;;;56734:14:0;;;;;;;;;;56641:115::o;59443:187::-;-1:-1:-1;;;;;59540:21:0;;;59502:7;59540:21;;;:10;:21;;;;;;59502:7;;59540:21;59579;;:43;;59615:7;59579:43;;;-1:-1:-1;59603:9:0;;59572:50;-1:-1:-1;59443:187:0:o;67758:164::-;-1:-1:-1;;;;;67817:23:0;;67813:51;;-1:-1:-1;67854:10:0;67813:51;67882:32;67892:10;67904:9;67882;:32::i;:::-;67758:164;:::o;46013:166::-;16467:14;;46099:4;;16467:30;:14;16333:1;16467:30;16459:39;;;;;;16509:14;:25;;-1:-1:-1;;16509:25:0;16376:1;16509:25;;;46123:48:::1;46136:6:::0;46144:14;46160:10:::1;46123:12;:48::i;:::-;46116:55;;16557:14:::0;:29;;-1:-1:-1;;16557:29:0;16333:1;16557:29;;;46013:166;;-1:-1:-1;;46013:166:0:o;19010:106::-;-1:-1:-1;;;;;18733:27:0;;19068:4;18733:27;;;:19;:27;;;;;;19092:16;18652:116;56154:198;56238:5;;56207:4;56280:21;;;:13;:21;;;;;;;;56254:47;;;;;;;;;;;;;;;-1:-1:-1;;;56254:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56207:4;;56238:5;56319:25;56254:47;56342:1;56319:10;:25::i;:::-;56312:32;56154:198;-1:-1:-1;;;;56154:198:0:o;53601:140::-;53676:4;53700:33;53716:8;53726:6;53700:15;:33::i;62000:127::-;62070:4;62094:25;62109:9;62094:14;:25::i;53937:880::-;53996:4;54030:12;54020:6;:22;;54013:30;;;;:::i;:::-;54068:5;;54054:11;54104:33;54122:6;54068:5;54104:17;:33::i;:::-;54150:18;54171:27;;;:13;:27;;;;;;;;54150:48;;;;;;;;;;;;;;;-1:-1:-1;;;54150:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54084:53;;-1:-1:-1;54235:21:0;;;54231:465;;;54273:23;54299:13;54273:23;54313:16;:12;54328:1;54313:16;:::i;:::-;54299:31;;;;;;;;;;;;;;-1:-1:-1;54299:31:0;54273:57;;;;;;;;;;;;;;;-1:-1:-1;;;54273:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54349:9;;;54273:57;;-1:-1:-1;54349:27:0;54345:155;;54474:5;:9;;;54457:10;:14;;;:26;;;;:::i;:::-;54443:5;:8;;;54427:10;:13;;;:24;;;;:::i;:::-;54413:9;;;;54404:18;;:6;:18;:::i;:::-;54403:49;;;;:::i;:::-;54402:82;;;;:::i;:::-;54397:87;;54345:155;54258:253;54231:465;;;54549:12;54536:5;:9;;;:25;54532:153;;54659:9;;;;54644:24;;:12;:24;:::i;:::-;54630:8;;;;54612:26;;:15;:26;:::i;:::-;54598:9;;;;54589:18;;:6;:18;:::i;:::-;54588:51;;;;:::i;:::-;54587:82;;;;:::i;:::-;54582:87;;54532:153;54777:32;54788:5;54806:2;54795:5;:8;;;:13;;;;:::i;:::-;54777:10;:32::i;:::-;54770:39;53937:880;-1:-1:-1;;;;;;53937:880:0:o;57177:147::-;57250:5;;-1:-1:-1;;;;;57250:5:0;57236:10;:19;57228:28;;;;;;57291:21;;;;:11;:21;;;;;;:25;;57315:1;;57291:25;:::i;:::-;57267:21;;;;:11;:21;;;;;;:49;57177:147::o;59831:499::-;-1:-1:-1;;;;;59928:23:0;;59889:4;59928:23;;;:14;:23;;;;;;;;59966:17;;;59962:58;;-1:-1:-1;60007:1:0;;59831:499;-1:-1:-1;;59831:499:0:o;59962:58::-;-1:-1:-1;;;;;60057:20:0;;60030:24;60057:20;;;:11;:20;;;;;60030:24;60078:16;60093:1;60078:12;:16;:::i;:::-;60057:38;;;;;;;;;;;;;;;:47;;60030:74;;60115:10;60145:6;60140:160;60161:16;;60157:20;;60140:160;;;60199:8;60210:9;60220:1;60210:12;;;;;;;;:::i;:::-;;;;;;;;;60199:23;;60253:35;60267:3;60272:15;60253:13;:35::i;:::-;60245:43;;:5;:43;:::i;:::-;60237:51;;60184:116;60179:3;;;;;:::i;:::-;;;;60140:160;;;-1:-1:-1;60317:5:0;59831:499;-1:-1:-1;;;;59831:499:0:o;46803:503::-;16467:14;;:30;:14;16333:1;16467:30;16459:39;;;;;;16509:14;:25;;-1:-1:-1;;16509:25:0;16376:1;16509:25;;;46896:40:::1;46915:10;46927:8:::0;46896:18:::1;:40::i;:::-;46889:48;;;;:::i;:::-;46950:28;46981:16:::0;;;:6:::1;:16;::::0;;;;;;;;46950:47;;;;::::1;::::0;;;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;47017:10;47010:18:::1;;;;:::i;:::-;47092:1;47075:7;:14;;;:18;;;47067:53;;;::::0;-1:-1:-1;;;47067:53:0;;11742:2:1;47067:53:0::1;::::0;::::1;11724:21:1::0;11781:2;11761:18;;;11754:30;-1:-1:-1;;;11800:18:1;;;11793:52;11862:18;;47067:53:0::1;11540:346:1::0;47067:53:0::1;47153:15;47139:7;:11;;;:29;47131:78;;;;-1:-1:-1::0;;;47131:78:0::1;;;;;;;:::i;:::-;47222:76;47235:8;47245:6;47253:1;47256:7;47265:32;47222:12;:76::i;:::-;-1:-1:-1::0;;16557:14:0;:29;;-1:-1:-1;;16557:29:0;16333:1;16557:29;;;-1:-1:-1;46803:503:0:o;22148:301::-;22304:10;-1:-1:-1;;;;;22291:23:0;;;22284:31;;;;:::i;:::-;22343:10;22326:28;;;;:16;:28;;;;;;;;-1:-1:-1;;;;;22326:39:0;;;;;;;;;;;;:51;;-1:-1:-1;;22326:51:0;;;;;;;;;;22393:48;;540:41:1;;;22326:39:0;;22343:10;22393:48;;513:18:1;22393:48:0;;;;;;;22148:301;;:::o;47442:724::-;16467:14;;:30;:14;16333:1;16467:30;16459:39;;;;;;16509:14;:25;;-1:-1:-1;;16509:25:0;16376:1;16509:25;;;47548:40:::1;47567:10;47579:8:::0;47548:18:::1;:40::i;:::-;47541:48;;;;:::i;:::-;47602:28;47633:16:::0;;;:6:::1;:16;::::0;;;;;;;47602:47;;;;::::1;::::0;;;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;;;;34595:7:::1;::::0;47680:32:::1;47698:14:::0;47680:15:::1;:32;:::i;:::-;47679:41;;;;:::i;:::-;:48;;;;:::i;:::-;47660:67;;47799:15;47785:7;:11;;;:29;47777:54;;;::::0;-1:-1:-1;;;47777:54:0;;12498:2:1;47777:54:0::1;::::0;::::1;12480:21:1::0;12537:2;12517:18;;;12510:30;-1:-1:-1;;;12556:18:1;;;12549:42;12608:18;;47777:54:0::1;12296:336:1::0;47777:54:0::1;47867:1;47850:7;:14;;;:18;;;47842:48;;;::::0;-1:-1:-1;;;47842:48:0;;12839:2:1;47842:48:0::1;::::0;::::1;12821:21:1::0;12878:2;12858:18;;;12851:30;-1:-1:-1;;;12897:18:1;;;12890:47;12954:18;;47842:48:0::1;12637:341:1::0;47842:48:0::1;47923:7;:11;;;47909;:25;47901:69;;;::::0;-1:-1:-1;;;47901:69:0;;13185:2:1;47901:69:0::1;::::0;::::1;13167:21:1::0;13224:2;13204:18;;;13197:30;13263:33;13243:18;;;13236:61;13314:18;;47901:69:0::1;12983:355:1::0;47901:69:0::1;48004:25;34642:15;48004;:25;:::i;:::-;47989:11;:40;;47981:83;;;::::0;-1:-1:-1;;;47981:83:0;;13545:2:1;47981:83:0::1;::::0;::::1;13527:21:1::0;13584:2;13564:18;;;13557:30;13623:32;13603:18;;;13596:60;13673:18;;47981:83:0::1;13343:354:1::0;47981:83:0::1;48077:81;48090:8;48100:1;48103:11;48116:7;48125:32;48077:12;:81::i;:::-;-1:-1:-1::0;;16557:14:0;:29;;-1:-1:-1;;16557:29:0;16333:1;16557:29;;;-1:-1:-1;;47442:724:0:o;28033:998::-;28183:47;28197:5;28204:3;28209:8;28219:10;28183:13;:47::i;:::-;27151:20;;27199:8;28243:781;;28389:73;;-1:-1:-1;;;28389:73:0;;-1:-1:-1;;;;;28389:37:0;;;;;:73;;28427:10;;28439:5;;28446:8;;28456:5;;28389:73;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;28389:73:0;;;;;;;;-1:-1:-1;;28389:73:0;;;;;;;;;;;;:::i;:::-;;;28385:628;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28730:6;:13;28747:1;28730:18;28726:272;;28773:60;;-1:-1:-1;;;28773:60:0;;14652:2:1;28773:60:0;;;14634:21:1;14691:2;14671:18;;;14664:30;14730:34;14710:18;;;14703:62;-1:-1:-1;;;14781:18:1;;;14774:48;14839:19;;28773:60:0;14450:414:1;28726:272:0;28948:6;28942:13;28933:6;28929:2;28925:15;28918:38;28385:628;-1:-1:-1;;;;;;28512:58:0;;-1:-1:-1;;;28512:58:0;28508:155;;28595:48;;-1:-1:-1;;;28595:48:0;;15071:2:1;28595:48:0;;;15053:21:1;15110:2;15090:18;;;15083:30;15149:34;15129:18;;;15122:62;-1:-1:-1;;;15200:18:1;;;15193:36;15246:19;;28595:48:0;14869:402:1;28508:155:0;28463:215;28385:628;28033:998;;;;:::o;56892:122::-;56966:5;;-1:-1:-1;;;;;56966:5:0;56952:10;:19;56944:28;;;;;;57001:5;56983:15;;;:5;:15;;;;;:23;;-1:-1:-1;;56983:23:0;;;56892:122::o;43967:106::-;44009:56;44021:1;44024:19;;;;;;;;44038:1;44024:19;;;;;;44041:1;44024:19;;;44045;;;;;;;;44059:1;44045:19;;;;;;44062:1;44045:19;;;44009:11;:56::i;:::-;43967:106::o;67930:1197::-;68236:4;;;;;;;;;;;;-1:-1:-1;;;68236:4:0;;;;;68277:7;;;;;;;;;;-1:-1:-1;;;68277:7:0;;;;68157:208;;58359:80;68157:208;;;15535:25:1;68220:22:0;15576:18:1;;;15569:34;68261:25:0;15619:18:1;;;15612:34;68305:13:0;15662:18:1;;;15655:34;68345:4:0;15705:19:1;;;;15698:61;;;;68157:208:0;;;;;;;;;;15507:19:1;;;68157:208:0;;68133:243;;;;;;58579:71;68432:57;;;16001:25:1;-1:-1:-1;;;;;16062:32:1;;16042:18;;;16035:60;16111:18;;;16104:34;;;16154:18;;;;16147:34;;;68432:57:0;;;;;;;;;;15973:19:1;;;68432:57:0;;;68408:92;;;;;;;;;;-1:-1:-1;;;68552:57:0;;;16450:27:1;16493:11;;;16486:27;;;16529:12;;;16522:28;;;68133:243:0;;-1:-1:-1;;16566:12:1;;68552:57:0;;;-1:-1:-1;;68552:57:0;;;;;;;;;68528:92;;68552:57;68528:92;;;;68631:17;68651:26;;;;;;;;;16816:25:1;;;16889:4;16877:17;;16857:18;;;16850:45;;;;16911:18;;;16904:34;;;16954:18;;;16947:34;;;68528:92:0;;-1:-1:-1;68631:17:0;68651:26;;16788:19:1;;68651:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;68651:26:0;;-1:-1:-1;;68651:26:0;;;-1:-1:-1;;;;;;;68710:23:0;;68688:119;;;;-1:-1:-1;;;68688:119:0;;17194:2:1;68688:119:0;;;17176:21:1;17233:2;17213:18;;;17206:30;17272:34;17252:18;;;17245:62;-1:-1:-1;;;17323:18:1;;;17316:44;17377:19;;68688:119:0;16992:410:1;68688:119:0;-1:-1:-1;;;;;68849:17:0;;;;;;:6;:17;;;;;:19;;;;;;:::i;:::-;;;;;68840:5;:28;68818:120;;;;-1:-1:-1;;;68818:120:0;;17609:2:1;68818:120:0;;;17591:21:1;17648:2;17628:18;;;17621:30;17687:34;17667:18;;;17660:62;-1:-1:-1;;;17738:18:1;;;17731:40;17788:19;;68818:120:0;17407:406:1;68818:120:0;68990:6;68971:15;:25;;68949:121;;;;-1:-1:-1;;;68949:121:0;;18020:2:1;68949:121:0;;;18002:21:1;18059:2;18039:18;;;18032:30;18098:34;18078:18;;;18071:62;-1:-1:-1;;;18149:18:1;;;18142:44;18203:19;;68949:121:0;17818:410:1;68949:121:0;69088:31;69098:9;69109;69088;:31::i;:::-;69081:38;;;;67930:1197;;;;;;;:::o;17320:428::-;17441:1;17410:19;;;:9;:19;;;;;;17376:13;;-1:-1:-1;;;;;17410:19:0;17402:73;;;;-1:-1:-1;;;17402:73:0;;18435:2:1;17402:73:0;;;18417:21:1;18474:2;18454:18;;;18447:30;18513:29;18493:18;;;18486:57;18560:18;;17402:73:0;18233:351:1;17402:73:0;17486:28;17517:16;;;:6;:16;;;;;;;;;17486:47;;;;;;;;;;;;;;;;;;;;;17563:8;;-1:-1:-1;;;;;17563:8:0;17551:31;17524:8;17620:40;17524:8;17644:15;17620:13;:40::i;:::-;17675:11;;;;17713:14;;17551:189;;;;;;-1:-1:-1;;;;;;17551:189:0;;;;;;18820:25:1;;;;18861:18;;;18854:34;;;;18904:18;;;18897:34;17706:22:0;;18947:18:1;;;18940:34;18792:19;;17551:189:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;17551:189:0;;;;;;;;;;;;:::i;57332:722::-;57397:18;;;;:11;:18;;;;;;:23;:40;;;;-1:-1:-1;57425:12:0;;;;:5;:12;;;;;;;;57424:13;57397:40;57389:61;;;;-1:-1:-1;;;57389:61:0;;;;;;;:::i;:::-;57478:3;57469:5;:12;57461:21;;;;;;57501:37;57520:10;57532:5;57501:18;:37::i;:::-;57493:46;;;;;;57558:35;57577:10;57589:3;57558:18;:35::i;:::-;57550:44;;;;;;57607:29;57639:13;;;:6;:13;;;;;;;;57607:45;;;;;;;;;;;;;;;;;;;;;;;;;;57695:11;;;;;;;;;57663:43;;;;;;;;;;;;;;;;;;;;;;;;57743:15;;57782:12;;57607:45;;57663:43;;57736:23;;;;-1:-1:-1;57782:28:0;:58;;57828:8;:12;;;57782:58;;;57813:8;:12;;;57782:58;57869:19;;;;;;;;-1:-1:-1;57869:19:0;;;;;;;;;;57853:13;;;:6;:13;;;;;:35;;;;-1:-1:-1;;;;;;57853:35:0;-1:-1:-1;;;;;57853:35:0;;;;;;;-1:-1:-1;57853:35:0;;;;;;;57928:19;;;;;;;;;;;;;;;57771:69;;-1:-1:-1;57899:49:0;;57853:13;;57918:8;;57899:11;:49::i;:::-;57959:12;57965:5;57959;:12::i;:::-;57982:64;57995:3;58000:6;58008:3;58013:8;58023:22;57982:12;:64::i;46447:176::-;16467:14;;46550:4;;16467:30;:14;16333:1;16467:30;16459:39;;;;;;16509:14;:25;;-1:-1:-1;;16509:25:0;16376:1;16509:25;;;46574:41:::1;46587:6:::0;46595:14;46611:3;46574:12:::1;:41::i;:::-;46567:48;;16557:14:::0;:29;;-1:-1:-1;;16557:29:0;16333:1;16557:29;;;46447:176;;-1:-1:-1;;;46447:176:0:o;51463:130::-;51534:4;51558:27;51572:8;51582:2;51558:13;:27::i;51256:199::-;51316:4;51337:26;;;:16;:26;;;;;;51367:12;51337:42;;51333:56;;-1:-1:-1;51388:1:0;;51256:199;-1:-1:-1;51256:199:0:o;51333:56::-;51407:40;51421:8;51431:15;51407:13;:40::i;44398:433::-;16467:14;;:30;:14;16333:1;16467:30;16459:39;;;;;;16509:14;:25;;-1:-1:-1;;16509:25:0;16376:1;16509:25;;;:14;44511:16;;;:6:::1;:16;::::0;;;;;;;;44480:47;;;;::::1;::::0;;;;;::::1;;::::0;;16509:25;44480:47:::1;::::0;;;::::1;::::0;44548:10;44540:19:::1;;;::::0;::::1;;44623:1;44606:7;:14;;;:18;;;44598:53;;;::::0;-1:-1:-1;;;44598:53:0;;11742:2:1;44598:53:0::1;::::0;::::1;11724:21:1::0;11781:2;11761:18;;;11754:30;-1:-1:-1;;;11800:18:1;;;11793:52;11862:18;;44598:53:0::1;11540:346:1::0;44598:53:0::1;44684:15;44670:7;:11;;;:29;44662:78;;;;-1:-1:-1::0;;;44662:78:0::1;;;;;;;:::i;:::-;44751:72;44764:8;44774:6;44782:1;44785:7;44794:28;44751:12;:72::i;57022:147::-:0;57095:5;;-1:-1:-1;;;;;57095:5:0;57081:10;:19;57073:28;;;;;;57136:21;;;;:11;:21;;;;;;:25;;57160:1;57136:25;:::i;56764:120::-;56837:5;;-1:-1:-1;;;;;56837:5:0;56823:10;:19;56815:28;;;;;;56854:15;;;;:5;:15;;;;;:22;;-1:-1:-1;;56854:22:0;56872:4;56854:22;;;56764:120::o;24274:892::-;24428:21;;;;:11;:21;;;;;;:26;:46;;;;-1:-1:-1;24459:15:0;;;;:5;:15;;;;;;;;24458:16;24428:46;24420:67;;;;-1:-1:-1;;;24420:67:0;;;;;;;:::i;:::-;24537:37;24556:7;24565:8;24537:18;:37::i;:::-;24529:46;;;;;;24657:31;24672:5;24679:8;24657:14;:31::i;:::-;24763:33;24780:5;24787:8;24763:16;:33::i;:::-;24836:63;24856:16;24866:5;24856:9;:16::i;:::-;24874:14;24884:3;24874:9;:14::i;:::-;24890:8;24836:19;:63::i;:::-;24930:26;24942:3;24947:8;24930:11;:26::i;:::-;25042;;;;:16;:26;;;;;;25071:12;25042:41;;25128:30;25059:8;;-1:-1:-1;;;;;25128:30:0;;;;;;;;;;;24274:892;;;;:::o;23267:422::-;23351:4;23384:19;;;:9;:19;;;;;;;;;23501:13;:23;;;;;;-1:-1:-1;;;;;23384:19:0;;;23567:23;;;:16;:23;;;;;23436:17;;;23566:35;;;;;;;;;23384:19;;23436:17;;;;23501:23;;;;23489:35;;23566;;23436:17;;23619:35;;;23637:17;23619:35;:62;;;;23658:23;23619:62;23612:69;23267:422;-1:-1:-1;;;;;;;23267:422:0:o;36228:5882::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36520:5:0;;36442:17;;;;36542:13;;36538:1170;;36684:15;36667:10;:14;;;:32;:57;;;;;36723:1;36703:10;:17;;;:21;;;36667:57;36663:234;;;36759:17;;:28;;34700:15;;36759:28;:::i;:::-;36745:42;;:11;;;;:42;;;;36847:14;;;:32;;36864:15;;36847:32;:::i;:::-;36819:5;:11;;;:62;;;;:::i;:::-;36806:75;;;;36663:234;36932:15;36915:10;:14;;;:32;:57;;;;;36971:1;36951:10;:17;;;:21;;;36915:57;36911:234;;;37007:17;;:28;;34700:15;;37007:28;:::i;:::-;36993:42;;:11;;;;:42;;;;37095:14;;;:32;;37112:15;;37095:32;:::i;:::-;37067:5;:11;;;:62;;;;:::i;:::-;37054:75;;;;36911:234;37413:14;;;;;37399:29;;;;:13;:29;;;;;;37447:14;;;;37399:29;;;;;;-1:-1:-1;37447:19:0;37443:254;;37509:10;:14;;;37491:10;:14;;;:32;37487:195;;37561:10;37548:23;;37487:195;;;37647:14;;;;;37633:29;;;;:13;:29;;;;;;;;;;-1:-1:-1;37487:195:0;37746:66;;;;;;;;37720:23;37746:66;;;;;;;37776:15;37746:66;;;;;;;37798:12;37746:66;;;;37827:10;;37823:77;;-1:-1:-1;37867:21:0;;;;:13;:21;;;;;;;;;37854:34;;;;;;;;;;;;;;;-1:-1:-1;;;37854:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37823:77;37933:13;;;;:10;37910:20;38276:15;:31;-1:-1:-1;38272:160:0;;;38406:13;;;;38388:31;;:15;:31;:::i;:::-;38368:14;;;;38353:29;;:12;:29;:::i;:::-;38339:44;;34758:7;38339:44;:::i;:::-;38338:82;;;;:::i;:::-;38324:96;;38272:160;38671:8;34595:7;38683:22;34595:7;38683:15;:22;:::i;:::-;38682:31;;;;:::i;:::-;38671:42;;38733:6;38728:1383;38749:3;38745:1;:7;38728:1383;;;38955:11;34595:7;38955:11;;:::i;:::-;;;38985:14;39032:15;39026:3;:21;39022:168;;;39078:15;39072:21;;39022:168;;;-1:-1:-1;39152:18:0;;;;:13;:18;;;;;;;;39022:168;39260:21;39266:15;39260:3;:21;:::i;:::-;39227:10;:16;;;:56;;;;:::i;:::-;39208:75;;:10;;:75;;;;;:::i;:::-;;;;;-1:-1:-1;39302:16:0;;;:27;;39322:7;;39302:16;:27;;39322:7;;39302:27;:::i;:::-;;;;;;;;39352:15;;39370:1;39352:19;;;39348:127;;-1:-1:-1;39348:127:0;;39454:1;39436:19;;39348:127;39516:1;39497:10;:16;;;:20;;;39493:147;;;39619:1;39600:16;;;:20;39493:147;39698:13;;;;:19;;;39800:21;;;39676:3;;-1:-1:-1;39676:3:0;;34758:7;;39794:27;;39676:3;39794:27;:::i;:::-;39779:43;;:11;:43;:::i;:::-;39778:58;;;;:::i;:::-;39753:18;:22;;;:83;;;;:::i;:::-;39736:14;;;:100;39855:11;39865:1;39855:11;;:::i;:::-;;;39896:15;39889:3;:22;39885:211;;-1:-1:-1;39953:12:0;39936:14;;;:29;39988:5;;39885:211;40042:21;;;;:13;:21;;;;;;;;;:34;;;;;;-1:-1:-1;;;;;40042:34:0;;;-1:-1:-1;;;40042:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;38754:3:0;;;:::i;:::-;;;38728:1383;;;-1:-1:-1;;40134:5:0;:14;;;40217:13;;40213:483;;40425:5;:11;;;40411:5;:11;;;:25;;;;:::i;:::-;40390:10;:16;;:47;;;;;;;:::i;:::-;;;;;-1:-1:-1;40485:10:0;;40472;;:23;;40485:10;40472:23;:::i;:::-;40452:44;;:10;;:44;;;;;:::i;:::-;;;;;;;;40515:16;;;;40534:1;40515:20;;;40511:81;;-1:-1:-1;40511:81:0;;40575:1;40556:16;;;:20;40511:81;40628:1;40610:10;:15;;;:19;;;40606:79;;;40668:1;40650:19;;40606:79;40758:21;;;;:13;:21;;;;;;;;;:34;;;;;;-1:-1:-1;;;;;40758:34:0;;;-1:-1:-1;;;40758:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;40809:13;;40805:1298;;41049:15;41032:10;:14;;;:32;41028:402;;;41179:11;;;;41165:25;;;;:::i;:::-;;;41231:10;:14;;;41213:10;:14;;;:32;41209:145;;41284:11;;;;41270:25;;;;:::i;:::-;;;41209:145;41386:14;;;;;41372:29;;;;:13;:29;;;;;;:42;;-1:-1:-1;;;;;;41372:42:0;-1:-1:-1;;;;;41372:42:0;;;;;41028:402;41467:15;41450:10;:14;;;:32;41446:344;;;41524:10;:14;;;41507:10;:14;;;:31;41503:209;;;41577:11;;;;41563:25;;;;:::i;:::-;41664:14;;;;;41650:29;;;;:13;:29;;;;;;:42;;-1:-1:-1;;;;;;41650:42:0;-1:-1:-1;;;;;41650:42:0;;;;;;-1:-1:-1;41503:209:0;41844:15;41862:26;;;:16;:26;;;;;;:30;;41891:1;41862:30;:::i;:::-;41844:48;;41938:10;41909:16;:26;41926:8;41909:26;;;;;;;;;;;:39;;;;41974:15;41963:5;:8;;:26;;;;;42016:12;42004:5;:9;;:24;;;;;42086:5;42043:18;:28;42062:8;42043:28;;;;;;;;;;;42072:10;42043:40;;;;;;;:::i;:::-;:48;;;;;;-1:-1:-1;;;;;42043:48:0;;;-1:-1:-1;;;42043:48:0;;;;:40;;;;;;;;;:48;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;40805:1298:0;36373:5737;;;;;;;;;36228:5882;;;:::o;33552:486::-;33610:40;33629:10;33641:8;33610:18;:40::i;:::-;33602:85;;;;-1:-1:-1;;;33602:85:0;;21644:2:1;33602:85:0;;;21626:21:1;;;21663:18;;;21656:30;21722:34;21702:18;;;21695:62;21774:18;;33602:85:0;21442:356:1;33602:85:0;33700:13;18383:19;;;:9;:19;;;;;;-1:-1:-1;;;;;18383:19:0;;33773:29;;18383:19;33773:7;:29::i;:::-;33844:59;33864:16;33874:5;33864:9;:16::i;:::-;33890:1;33894:8;33844:19;:59::i;:::-;33939:38;33956:10;33968:8;33939:16;:38::i;:::-;33993:37;;34021:8;;34017:1;;-1:-1:-1;;;;;33993:37:0;;;;;34017:1;;33993:37;33591:447;33552:486;:::o;50717:531::-;50787:4;50818:26;;;:16;:26;;;;;;50859:11;;;50855:386;;50894:1;50887:8;;;;;50855:386;50928:23;50954:28;;;:18;:28;;;;;50983:6;50954:36;;;;;;;:::i;:::-;50928:62;;;;;;;;50954:36;;;;;;;;;50928:62;;;;;;;;-1:-1:-1;;;50928:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;51050:34:0;;51057:2;51050:34;:::i;:::-;51024:10;:16;;;:61;;;;:::i;:::-;51005:80;;:10;;:80;;;;;:::i;:::-;;;;;;;;51104:15;;51122:1;51104:19;;;51100:79;;-1:-1:-1;51100:79:0;;51162:1;51144:19;;51100:79;51212:15;51205:23;;;-1:-1:-1;51193:36:0;;-1:-1:-1;51193:36:0;67169:441;67371:23;67397:20;67407:9;67397;:20::i;:::-;-1:-1:-1;;;;;67430:21:0;;;;;;;:10;:21;;;;;;:33;;-1:-1:-1;;;;;;67430:33:0;;;;;;;;;;67481:54;;67371:46;;-1:-1:-1;67430:33:0;67481:54;;;;;;67430:21;67481:54;67546:56;67564:9;67575:15;67592:9;67546:17;:56::i;45099:678::-;45186:4;;34595:7;;45223:32;45241:14;45223:15;:32;:::i;:::-;45222:41;;;;:::i;:::-;:48;;;;:::i;:::-;45203:67;;45337:1;45328:6;:10;45320:19;;;;;;45400:15;45386:11;:29;45378:80;;;;-1:-1:-1;;;45378:80:0;;22277:2:1;45378:80:0;;;22259:21:1;22316:2;22296:18;;;22289:30;22355:34;22335:18;;;22328:62;-1:-1:-1;;;22406:18:1;;;22399:36;22452:19;;45378:80:0;22075:402:1;45378:80:0;45492:25;34642:15;45492;:25;:::i;:::-;45477:11;:40;;45469:83;;;;-1:-1:-1;;;45469:83:0;;13545:2:1;45469:83:0;;;13527:21:1;13584:2;13564:18;;;13557:30;13623:32;13603:18;;;13596:60;13673:18;;45469:83:0;13343:354:1;45469:83:0;45567:7;;45565:9;;;;;:::i;:::-;;;;-1:-1:-1;45601:7:0;;45619:20;45625:3;45601:7;45619:5;:20::i;:::-;-1:-1:-1;45696:16:0;;;;:6;:16;;;;;;;;;45652:91;;;;;;;;;;;;;;;;;;;;;;;;;;;;45665:8;;45675:6;;45683:11;;45652:12;:91::i;:::-;45761:8;45099:678;-1:-1:-1;;;;;45099:678:0:o;55072:791::-;55143:4;55160:23;55186:5;55160:31;;55202:8;34595:7;;55214:10;:13;;;:20;;;;:::i;:::-;55213:29;;;;:::i;:::-;55202:40;;55258:6;55253:472;55274:3;55270:1;:7;55253:472;;;55299:11;34595:7;55299:11;;:::i;:::-;;;55325:14;55368:1;55362:3;:7;55358:124;;;55396:1;55390:7;;55358:124;;;-1:-1:-1;55448:18:0;;;;:13;:18;;;;;;;;55358:124;55554:13;;;;55548:19;;:3;:19;:::i;:::-;55515:10;:16;;;:54;;;;:::i;:::-;55496:73;;:10;;:73;;;;;:::i;:::-;;;;;-1:-1:-1;55588:8:0;;;55584:54;;55617:5;;;55584:54;55672:7;55652:10;:16;;:27;;;;;;;:::i;:::-;;;;;-1:-1:-1;;55694:13:0;;;:19;;;55279:3;;;:::i;:::-;;;55253:472;;;;55759:1;55741:10;:15;;;:19;;;55737:71;;;55795:1;55777:19;;55737:71;-1:-1:-1;55838:15:0;-1:-1:-1;;;;;55825:30:0;;55072:791;-1:-1:-1;;;55072:791:0:o;51903:1690::-;51979:4;52117:12;52107:6;:22;;52100:30;;;;:::i;:::-;52169:9;52205:26;;;:16;:26;;;;;;52169:9;52242:391;52263:3;52259:1;:7;52242:391;;;52358:4;52350;:12;52346:58;52383:5;52346:58;52418:9;52450:1;52431:11;52438:4;52431;:11;:::i;:::-;:15;;52445:1;52431:15;:::i;:::-;52430:21;;;;:::i;:::-;52470:28;;;;:18;:28;;;;;52418:33;;-1:-1:-1;52512:6:0;;52418:33;52470:34;;;;;;;:::i;:::-;;;;:38;;;:48;52466:156;;52546:4;52539:11;;52466:156;;;52598:8;52605:1;52598:4;:8;:::i;:::-;52591:15;;52466:156;-1:-1:-1;52268:3:0;;;:::i;:::-;;;52242:391;;;-1:-1:-1;52645:19:0;52667:28;;;:18;:28;;;;;52696:4;52667:34;;;;;;;:::i;:::-;52645:56;;;;;;;;52667:34;;;;;;;;;52645:56;;;;;;;;-1:-1:-1;;;52645:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52731:5;;52645:56;;-1:-1:-1;;52761:36:0;52779:6;52731:5;52761:17;:36::i;:::-;52808:20;52831:21;;;:13;:21;;;;;;;;52808:44;;;;;;;;;;;;;;;-1:-1:-1;;;52808:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52747:50;;-1:-1:-1;52808:20:0;52917:18;;;52913:311;;;52952:20;52975:13;52952:20;52989:10;:6;52998:1;52989:10;:::i;:::-;52975:25;;;;;;;;;;;;;;-1:-1:-1;52975:25:0;52952:48;;;;;;;;;;;;;;;-1:-1:-1;;;52952:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53039:11;;;52952:48;;-1:-1:-1;53025:25:0;;53039:11;53025:25;:::i;:::-;53015:35;;53084:7;:10;;;53071:7;:10;;;:23;;;;:::i;:::-;53065:29;;52937:169;52913:311;;;53152:11;;;;53137:26;;:12;:26;:::i;:::-;53127:36;;53202:7;:10;;;53184:15;:28;;;;:::i;:::-;53178:34;;52913:311;53252:10;;;;53277:12;;53273:99;;53353:7;53337;:11;;;53328:6;:20;;;;:::i;:::-;53321:28;;:3;:28;:::i;:::-;53320:40;;;;:::i;:::-;53306:54;;;;:::i;:::-;;;53273:99;53441:9;;;;53428:22;;:10;:22;:::i;:::-;53399:6;:12;;;:53;;;;:::i;:::-;53384:68;;:6;;:68;;;;;:::i;:::-;;;;;;;;53467:11;;53482:1;53467:16;;;;-1:-1:-1;53463:123:0;;-1:-1:-1;;53520:11:0;;-1:-1:-1;;;;;53507:26:0;;-1:-1:-1;53500:33:0;;-1:-1:-1;;;;;;53500:33:0;53463:123;53573:1;53566:8;;;;;;;;;;;;;49854:583;49933:4;;50012:9;49933:4;50032:376;50053:3;50049:1;:7;50032:376;;;50148:4;50140;:12;50136:58;50173:5;50136:58;50208:9;50240:1;50221:11;50228:4;50221;:11;:::i;:::-;:15;;50235:1;50221:15;:::i;:::-;50220:21;;;;:::i;:::-;50260:19;;;;:13;:19;;;;;:23;;;50208:33;;-1:-1:-1;50260:33:0;-1:-1:-1;50256:141:0;;50321:4;50314:11;;50256:141;;;50373:8;50380:1;50373:4;:8;:::i;:::-;50366:15;;50256:141;-1:-1:-1;50058:3:0;;;:::i;:::-;;;50032:376;;;-1:-1:-1;50425:4:0;;49854:583;-1:-1:-1;;;;49854:583:0:o;42453:1357::-;42733:6;;42687:14;;42761:22;42777:6;42733;42761:22;:::i;:::-;42752:6;:31;-1:-1:-1;;;;;;;;;;;;;;;;;42875:14:0;;42891:11;;;;;42856:14;;;42836:67;;;;;42996:40;;43028:6;;42875:7;;42996:40;;43028:6;;42996:40;:::i;:::-;;;;;-1:-1:-1;43051:16:0;;43047:74;;43084:11;;;:25;;;43047:74;43131:16;;;;:6;:16;;;;;;;;:26;;;;-1:-1:-1;;;;;;43131:26:0;-1:-1:-1;;;;;43131:26:0;;;;;;;;;;-1:-1:-1;43131:26:0;;;;43409:42;43131:16;43431:10;43131:26;43409:11;:42::i;:::-;43479:10;43504:11;;;;;:53;;-1:-1:-1;43535:22:0;43519:12;:38;;;;;;;;:::i;:::-;;;43504:53;43500:149;;;43581:55;;-1:-1:-1;;;43581:55:0;;-1:-1:-1;;;;;22872:15:1;;;43581:55:0;;;22854:34:1;43622:4:0;22904:18:1;;;22897:43;22956:18;;;22949:34;;;43588:5:0;43581:26;;;;22789:18:1;;43581:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43574:63;;;;:::i;:::-;43698:7;:11;;;43674:4;-1:-1:-1;;;;;43666:75:0;;43680:8;43690:6;43711:12;43725:15;43666:75;;;;;;;;;:::i;:::-;;;;;;;;43757:45;43764:13;43779:22;43795:6;43764:13;43779:22;:::i;:::-;43757:45;;;10890:25:1;;;10946:2;10931:18;;10924:34;;;;10863:18;43757:45:0;;;;;;;42645:1165;;;;42453:1357;;;;;:::o;22597:324::-;22735:19;;;;:9;:19;;;;;;-1:-1:-1;;;;;22735:29:0;;;:19;;:29;22728:37;;;;:::i;:::-;22815:1;22780:23;;;:13;:23;;;;;;-1:-1:-1;;;;;22780:23:0;:37;22776:138;;22900:1;22866:23;;;:13;:23;;;;;:36;;-1:-1:-1;;;;;;22866:36:0;;;22776:138;22597:324;;:::o;33122:422::-;33260:19;;;;:9;:19;;;;;;-1:-1:-1;;;;;33260:28:0;;;:19;;:28;33253:36;;;;:::i;:::-;33359:1;33329:19;;;:9;:19;;;;;:32;;-1:-1:-1;;;;;;33329:32:0;;;33418:42;33444:5;33339:8;33418:25;:42::i;:::-;-1:-1:-1;;;;;33505:26:0;;;;;;:19;:26;;;;;:31;;33535:1;;33505:26;:31;;33535:1;;33505:31;:::i;:::-;;;;-1:-1:-1;;;;33122:422:0:o;62325:2026::-;62469:6;-1:-1:-1;;;;;62459:16:0;:6;-1:-1:-1;;;;;62459:16:0;;;:32;;;;;62490:1;62479:8;:12;62459:32;62455:1889;;;-1:-1:-1;;;;;62512:20:0;;;62508:837;;-1:-1:-1;;;;;62572:22:0;;62553:16;62572:22;;;:14;:22;;;;;;;;;62640:13;:135;;-1:-1:-1;;;;;62744:19:0;;;;;;:11;:19;;;;;;;;:22;;;;;;;;:31;;62640:135;;;-1:-1:-1;;;;;62677:19:0;;;;;;:11;:19;;;;;;62697:13;62709:1;62697:9;:13;:::i;:::-;62677:34;;;;;;;;;;;;;;;:43;;62640:135;62613:162;;62794:20;62817:34;62844:6;62817:26;:34::i;:::-;-1:-1:-1;;;;;62897:19:0;;62870:24;62897:19;;;:11;:19;;;;;;;;:74;;;;;;;;;;62794:57;;-1:-1:-1;62897:83:0;;;;;63048:223;63069:16;;63065:20;;63048:223;;;63115:8;63126:9;63136:1;63126:12;;;;;;;;:::i;:::-;;;;;;;;;63115:23;;63172:8;63165:3;:15;63161:91;;63209:19;;;;;;;-1:-1:-1;63209:19:0;;;;;;;;;;63161:91;-1:-1:-1;63087:3:0;;;;:::i;:::-;;;;63048:223;;;-1:-1:-1;63316:13:0;:9;63328:1;63316:13;:::i;:::-;-1:-1:-1;;;;;63291:22:0;;;;;;:14;:22;;;;;:38;;-1:-1:-1;;63291:38:0;;;;;;;;;;;;-1:-1:-1;;;;62508:837:0;-1:-1:-1;;;;;63365:20:0;;;63361:972;;-1:-1:-1;;;;;63425:22:0;;63406:16;63425:22;;;:14;:22;;;;;;;;;63493:13;:135;;-1:-1:-1;;;;;63597:19:0;;;;;;:11;:19;;;;;;;;:22;;;;;;;;:31;;63493:135;;;-1:-1:-1;;;;;63530:19:0;;;;;;:11;:19;;;;;;63550:13;63562:1;63550:9;:13;:::i;:::-;63530:34;;;;;;;;;;;;;;;:43;;63493:135;63466:162;;63647:20;63670:34;63697:6;63670:26;:34::i;:::-;-1:-1:-1;;;;;63750:19:0;;63723:24;63750:19;;;:11;:19;;;;;;;;:74;;;;;;;;;;63929:16;;63647:57;;-1:-1:-1;63750:83:0;;;;;58801:4;;63929:20;;:16;:20;:::i;:::-;:37;;63899:146;;;;-1:-1:-1;;;63899:146:0;;;;;;;:::i;:::-;64069:6;64064:152;64085:16;;64081:20;;64064:152;;;64131:8;64142:9;64152:1;64142:12;;;;;;;;:::i;:::-;;;;;;;;;;;;;64177:19;;;;;;;;;;;;;;;;-1:-1:-1;64103:3:0;;;;:::i;:::-;;;;64064:152;;;-1:-1:-1;64234:24:0;;;;;;;;-1:-1:-1;64234:24:0;;;;;;;;;;;;64304:13;;:9;;:13;:::i;:::-;-1:-1:-1;;;;;64279:22:0;;;;;;:14;:22;;;;;:38;;;;;;;-1:-1:-1;;64279:38:0;;;;;;;;;-1:-1:-1;;;;62325:2026:0;;;:::o;30647:402::-;30807:1;30776:19;;;:9;:19;;;;;;-1:-1:-1;;;;;30776:19:0;:33;30769:41;;;;:::i;:::-;30850:19;;;;:9;:19;;;;;;;;:25;;-1:-1:-1;;;;;;30850:25:0;-1:-1:-1;;;;;30850:25:0;;;;;;;;18733:27;;;:19;:27;;;;;;;;30427:20;:25;;;;;:40;;;;;;;;:51;;;30489:27;;;:17;:27;;;;;:43;;;;31012:24;;;;;;:29;;-1:-1:-1;;30850:19:0;31012:29;;-1:-1:-1;;31012:29:0;:::i;64835:2326::-;65026:6;-1:-1:-1;;;;;65016:16:0;:6;-1:-1:-1;;;;;65016:16:0;;65012:2142;;-1:-1:-1;;;;;65053:20:0;;;65049:852;;-1:-1:-1;;;;;65113:22:0;;65094:16;65113:22;;;:14;:22;;;;;;;;;65181:13;:135;;-1:-1:-1;;;;;65285:19:0;;;;;;:11;:19;;;;;;;;:22;;;;;;;;:31;;65181:135;;;-1:-1:-1;;;;;65218:19:0;;;;;;:11;:19;;;;;;65238:13;65250:1;65238:9;:13;:::i;:::-;65218:34;;;;;;;;;;;;;;;:43;;65181:135;65154:162;;65335:20;65358:34;65385:6;65358:26;:34::i;:::-;-1:-1:-1;;;;;65438:19:0;;65411:24;65438:19;;;:11;:19;;;;;;;;:74;;;;;;;;;;65335:57;;-1:-1:-1;65438:83:0;;;;;65596:231;65617:16;;65613:20;;65596:231;;;65663:8;65674:9;65684:1;65674:12;;;;;;;;:::i;:::-;;;;;;;;;;;;;65713:14;;;:9;:14;;;;;;;;65674:12;;-1:-1:-1;;;;;;65713:14:0;;;:23;;;;65709:99;;65765:19;;;;;;;-1:-1:-1;65765:19:0;;;;;;;;;;65709:99;-1:-1:-1;65635:3:0;;;;:::i;:::-;;;;65596:231;;;-1:-1:-1;65872:13:0;:9;65884:1;65872:13;:::i;:::-;-1:-1:-1;;;;;65847:22:0;;;;;;:14;:22;;;;;:38;;-1:-1:-1;;65847:38:0;;;;;;;;;;;;-1:-1:-1;;;;65049:852:0;-1:-1:-1;;;;;65921:20:0;;;65917:1226;;-1:-1:-1;;;;;65981:22:0;;65962:16;65981:22;;;:14;:22;;;;;;;;;66049:13;:135;;-1:-1:-1;;;;;66153:19:0;;;;;;:11;:19;;;;;;;;:22;;;;;;;;:31;;66049:135;;;-1:-1:-1;;;;;66086:19:0;;;;;;:11;:19;;;;;;66106:13;66118:1;66106:9;:13;:::i;:::-;66086:34;;;;;;;;;;;;;;;:43;;66049:135;66022:162;;66203:20;66226:34;66253:6;66226:26;:34::i;:::-;-1:-1:-1;;;;;66306:19:0;;;66279:24;66306:19;;;:11;:19;;;;;;;;:74;;;;;;;;;;66431:26;;;;;:19;:26;;;;;;66506:16;;66203:57;;-1:-1:-1;66306:83:0;;;;;58801:4;;66506:34;;66431:26;;66506:34;:::i;:::-;:51;;66476:160;;;;-1:-1:-1;;;66476:160:0;;;;;;;:::i;:::-;66693:6;66688:152;66709:16;;66705:20;;66688:152;;;66755:8;66766:9;66776:1;66766:12;;;;;;;;:::i;:::-;;;;;;;;;;;;;66801:19;;;;;;;;;;;;;;;;-1:-1:-1;66727:3:0;;;;:::i;:::-;;;;66688:152;;;;66905:6;66900:169;66921:15;66917:1;:19;66900:169;;;-1:-1:-1;;;;;66977:27:0;;66966:8;66977:27;;;:20;:27;;;;;;;;:30;;;;;;;;67030:19;;;;;;;;;;;;;;;;67005:1;66938:3;67005:1;66938:3;:::i;:::-;;;;66900:169;;;-1:-1:-1;67114:13:0;:9;67126:1;67114:13;:::i;:::-;-1:-1:-1;;;;;67089:22:0;;;;;;:14;:22;;;;;:38;;;;;;;-1:-1:-1;;67089:38:0;;;;;;;;;-1:-1:-1;;;;;64835:2326:0;;;:::o;31389:426::-;31450:4;-1:-1:-1;;;;;31518:17:0;;31511:25;;;;:::i;:::-;31578:57;31606:1;31610:14;31620:3;31610:9;:14::i;31578:57::-;31708:26;31720:3;31725:8;31708:11;:26::i;:::-;31750:35;;31776:8;;-1:-1:-1;;;;;31750:35:0;;;31767:1;;31750:35;;31767:1;;31750:35;-1:-1:-1;31803:4:0;31389:426;;;;:::o;31995:1013::-;-1:-1:-1;;;;;18733:27:0;;32099:18;18733:27;;;:19;:27;;;;;;32120:19;;32138:1;;32120:19;:::i;:::-;32150:18;32171:27;;;:17;:27;;;;;;32099:40;;-1:-1:-1;32215:30:0;;;32211:790;;-1:-1:-1;;;;;32306:27:0;;32351:1;32306:27;;;:20;:27;;;;;;;;:42;;;;;;;;:46;;;32408:27;;;:17;:27;;;;;:31;32211:790;;;-1:-1:-1;;;;;32491:27:0;;;;32472:16;32491:27;;;:20;:27;;;;;;;;:42;;;;;;;;;;;32614;;;;;;:56;;;32726:30;;:17;:30;;;;;;:46;;;;32856;;;;32958:27;;;;;:31;31995:1013::o;64359:468::-;-1:-1:-1;;;;;64553:23:0;;64462:6;64553:23;;;:14;:23;;;;;;64504:15;;64553:23;;64607:17;;;;;:97;;-1:-1:-1;;;;;;64641:20:0;;;;;;:11;:20;;;;;64694:10;;64662:17;64678:1;64662:13;:17;:::i;:::-;64641:39;;;;;;;;;;;;;-1:-1:-1;64641:39:0;:49;:63;64607:97;64589:231;;;64738:17;64754:1;64738:13;:17;:::i;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;774:258::-;846:1;856:113;870:6;867:1;864:13;856:113;;;946:11;;;940:18;927:11;;;920:39;892:2;885:10;856:113;;;987:6;984:1;981:13;978:48;;;-1:-1:-1;;1022:1:1;1004:16;;997:27;774:258::o;1037:::-;1079:3;1117:5;1111:12;1144:6;1139:3;1132:19;1160:63;1216:6;1209:4;1204:3;1200:14;1193:4;1186:5;1182:16;1160:63;:::i;:::-;1277:2;1256:15;-1:-1:-1;;1252:29:1;1243:39;;;;1284:4;1239:50;;1037:258;-1:-1:-1;;1037:258:1:o;1300:220::-;1449:2;1438:9;1431:21;1412:4;1469:45;1510:2;1499:9;1495:18;1487:6;1469:45;:::i;1525:173::-;1593:20;;-1:-1:-1;;;;;1642:31:1;;1632:42;;1622:70;;1688:1;1685;1678:12;1622:70;1525:173;;;:::o;1703:254::-;1771:6;1779;1832:2;1820:9;1811:7;1807:23;1803:32;1800:52;;;1848:1;1845;1838:12;1800:52;1871:29;1890:9;1871:29;:::i;:::-;1861:39;1947:2;1932:18;;;;1919:32;;-1:-1:-1;;;1703:254:1:o;2159:180::-;2218:6;2271:2;2259:9;2250:7;2246:23;2242:32;2239:52;;;2287:1;2284;2277:12;2239:52;-1:-1:-1;2310:23:1;;2159:180;-1:-1:-1;2159:180:1:o;2552:186::-;2611:6;2664:2;2652:9;2643:7;2639:23;2635:32;2632:52;;;2680:1;2677;2670:12;2632:52;2703:29;2722:9;2703:29;:::i;2743:248::-;2811:6;2819;2872:2;2860:9;2851:7;2847:23;2843:32;2840:52;;;2888:1;2885;2878:12;2840:52;-1:-1:-1;;2911:23:1;;;2981:2;2966:18;;;2953:32;;-1:-1:-1;2743:248:1:o;3602:328::-;3679:6;3687;3695;3748:2;3736:9;3727:7;3723:23;3719:32;3716:52;;;3764:1;3761;3754:12;3716:52;3787:29;3806:9;3787:29;:::i;:::-;3777:39;;3835:38;3869:2;3858:9;3854:18;3835:38;:::i;:::-;3825:48;;3920:2;3909:9;3905:18;3892:32;3882:42;;3602:328;;;;;:::o;4320:118::-;4406:5;4399:13;4392:21;4385:5;4382:32;4372:60;;4428:1;4425;4418:12;4443:315;4508:6;4516;4569:2;4557:9;4548:7;4544:23;4540:32;4537:52;;;4585:1;4582;4575:12;4537:52;4608:29;4627:9;4608:29;:::i;:::-;4598:39;;4687:2;4676:9;4672:18;4659:32;4700:28;4722:5;4700:28;:::i;:::-;4747:5;4737:15;;;4443:315;;;;;:::o;5030:127::-;5091:10;5086:3;5082:20;5079:1;5072:31;5122:4;5119:1;5112:15;5146:4;5143:1;5136:15;5162:275;5233:2;5227:9;5298:2;5279:13;;-1:-1:-1;;5275:27:1;5263:40;;5333:18;5318:34;;5354:22;;;5315:62;5312:88;;;5380:18;;:::i;:::-;5416:2;5409:22;5162:275;;-1:-1:-1;5162:275:1:o;5442:186::-;5490:4;5523:18;5515:6;5512:30;5509:56;;;5545:18;;:::i;:::-;-1:-1:-1;5611:2:1;5590:15;-1:-1:-1;;5586:29:1;5617:4;5582:40;;5442:186::o;5633:888::-;5728:6;5736;5744;5752;5805:3;5793:9;5784:7;5780:23;5776:33;5773:53;;;5822:1;5819;5812:12;5773:53;5845:29;5864:9;5845:29;:::i;:::-;5835:39;;5893:38;5927:2;5916:9;5912:18;5893:38;:::i;:::-;5883:48;;5978:2;5967:9;5963:18;5950:32;5940:42;;6033:2;6022:9;6018:18;6005:32;6060:18;6052:6;6049:30;6046:50;;;6092:1;6089;6082:12;6046:50;6115:22;;6168:4;6160:13;;6156:27;-1:-1:-1;6146:55:1;;6197:1;6194;6187:12;6146:55;6233:2;6220:16;6258:48;6274:31;6302:2;6274:31;:::i;:::-;6258:48;:::i;:::-;6329:2;6322:5;6315:17;6369:7;6364:2;6359;6355;6351:11;6347:20;6344:33;6341:53;;;6390:1;6387;6380:12;6341:53;6445:2;6440;6436;6432:11;6427:2;6420:5;6416:14;6403:45;6489:1;6484:2;6479;6472:5;6468:14;6464:23;6457:34;6510:5;6500:15;;;;;5633:888;;;;;;;:::o;6526:618::-;6628:6;6636;6644;6652;6660;6668;6721:3;6709:9;6700:7;6696:23;6692:33;6689:53;;;6738:1;6735;6728:12;6689:53;6761:29;6780:9;6761:29;:::i;:::-;6751:39;;6837:2;6826:9;6822:18;6809:32;6799:42;;6888:2;6877:9;6873:18;6860:32;6850:42;;6942:2;6931:9;6927:18;6914:32;6986:4;6979:5;6975:16;6968:5;6965:27;6955:55;;7006:1;7003;6996:12;6955:55;6526:618;;;;-1:-1:-1;6526:618:1;;7081:3;7066:19;;7053:33;;7133:3;7118:19;;;7105:33;;-1:-1:-1;6526:618:1;-1:-1:-1;;6526:618:1:o;7149:322::-;7226:6;7234;7242;7295:2;7283:9;7274:7;7270:23;7266:32;7263:52;;;7311:1;7308;7301:12;7263:52;7347:9;7334:23;7324:33;;7404:2;7393:9;7389:18;7376:32;7366:42;;7427:38;7461:2;7450:9;7446:18;7427:38;:::i;:::-;7417:48;;7149:322;;;;;:::o;7476:260::-;7544:6;7552;7605:2;7593:9;7584:7;7580:23;7576:32;7573:52;;;7621:1;7618;7611:12;7573:52;7644:29;7663:9;7644:29;:::i;:::-;7634:39;;7692:38;7726:2;7715:9;7711:18;7692:38;:::i;:::-;7682:48;;7476:260;;;;;:::o;7741:350::-;7808:6;7816;7869:2;7857:9;7848:7;7844:23;7840:32;7837:52;;;7885:1;7882;7875:12;7837:52;7908:29;7927:9;7908:29;:::i;:::-;7898:39;;7987:2;7976:9;7972:18;7959:32;8031:10;8024:5;8020:22;8013:5;8010:33;8000:61;;8057:1;8054;8047:12;8096:127;8157:10;8152:3;8148:20;8145:1;8138:31;8188:4;8185:1;8178:15;8212:4;8209:1;8202:15;8228:221;8267:4;8296:10;8356;;;;8326;;8378:12;;;8375:38;;;8393:18;;:::i;:::-;8430:13;;8228:221;-1:-1:-1;;;8228:221:1:o;8454:127::-;8515:10;8510:3;8506:20;8503:1;8496:31;8546:4;8543:1;8536:15;8570:4;8567:1;8560:15;8586:191;8625:1;8651:10;8688:2;8685:1;8681:10;8710:3;8700:37;;8717:18;;:::i;:::-;8755:10;;8751:20;;;;;8586:191;-1:-1:-1;;8586:191:1:o;8782:127::-;8843:10;8838:3;8834:20;8831:1;8824:31;8874:4;8871:1;8864:15;8898:4;8895:1;8888:15;8914:127;8975:10;8970:3;8966:20;8963:1;8956:31;9006:4;9003:1;8996:15;9030:4;9027:1;9020:15;9046:331;9248:2;9230:21;;;9287:1;9267:18;;;9260:29;-1:-1:-1;;;9320:2:1;9305:18;;9298:38;9368:2;9353:18;;9046:331::o;9733:125::-;9773:4;9801:1;9798;9795:8;9792:34;;;9806:18;;:::i;:::-;-1:-1:-1;9843:9:1;;9733:125::o;10142:245::-;10209:6;10262:2;10250:9;10241:7;10237:23;10233:32;10230:52;;;10278:1;10275;10268:12;10230:52;10310:9;10304:16;10329:28;10351:5;10329:28;:::i;10969:128::-;11009:3;11040:1;11036:6;11033:1;11030:13;11027:39;;;11046:18;;:::i;:::-;-1:-1:-1;11082:9:1;;10969:128::o;11102:135::-;11141:3;11162:17;;;11159:43;;11182:18;;:::i;:::-;-1:-1:-1;11229:1:1;11218:13;;11102:135::o;11242:168::-;11282:7;11348:1;11344;11340:6;11336:14;11333:1;11330:21;11325:1;11318:9;11311:17;11307:45;11304:71;;;11355:18;;:::i;:::-;-1:-1:-1;11395:9:1;;11242:168::o;11415:120::-;11455:1;11481;11471:35;;11486:18;;:::i;:::-;-1:-1:-1;11520:9:1;;11415:120::o;11891:400::-;12093:2;12075:21;;;12132:2;12112:18;;;12105:30;12171:34;12166:2;12151:18;;12144:62;-1:-1:-1;;;12237:2:1;12222:18;;12215:34;12281:3;12266:19;;11891:400::o;13702:489::-;-1:-1:-1;;;;;13971:15:1;;;13953:34;;14023:15;;14018:2;14003:18;;13996:43;14070:2;14055:18;;14048:34;;;14118:3;14113:2;14098:18;;14091:31;;;13896:4;;14139:46;;14165:19;;14157:6;14139:46;:::i;14196:249::-;14265:6;14318:2;14306:9;14297:7;14293:23;14289:32;14286:52;;;14334:1;14331;14324:12;14286:52;14366:9;14360:16;14385:30;14409:5;14385:30;:::i;18985:635::-;19065:6;19118:2;19106:9;19097:7;19093:23;19089:32;19086:52;;;19134:1;19131;19124:12;19086:52;19167:9;19161:16;19200:18;19192:6;19189:30;19186:50;;;19232:1;19229;19222:12;19186:50;19255:22;;19308:4;19300:13;;19296:27;-1:-1:-1;19286:55:1;;19337:1;19334;19327:12;19286:55;19366:2;19360:9;19391:48;19407:31;19435:2;19407:31;:::i;19391:48::-;19462:2;19455:5;19448:17;19502:7;19497:2;19492;19488;19484:11;19480:20;19477:33;19474:53;;;19523:1;19520;19513:12;19474:53;19536:54;19587:2;19582;19575:5;19571:14;19566:2;19562;19558:11;19536:54;:::i;19625:305::-;19664:1;19706;19702:2;19691:17;19743:1;19739:2;19728:17;19764:3;19754:37;;19771:18;;:::i;:::-;-1:-1:-1;;;;;;19807:48:1;;-1:-1:-1;;19857:15:1;;19803:70;19800:96;;;19876:18;;:::i;:::-;19910:14;;;19625:305;-1:-1:-1;;;19625:305:1:o;19935:698::-;19974:7;20022:1;20018:2;20007:17;20059:1;20055:2;20044:17;-1:-1:-1;;;;;20142:1:1;20137:3;20133:11;20172:1;20167:3;20163:11;20219:3;20215:2;20211:12;20206:3;20203:21;20198:2;20194;20190:11;20186:39;20183:65;;;20228:18;;:::i;:::-;-1:-1:-1;;;;;;20334:1:1;20325:11;;20352;;;20374:13;;;20365:23;;20348:41;20345:67;;;20392:18;;:::i;:::-;20440:1;20435:3;20431:11;20421:21;;20489:3;20485:2;20480:13;20475:3;20471:23;20466:2;20462;20458:11;20454:41;20451:67;;;20498:18;;:::i;:::-;20565:3;20561:2;20556:13;20551:3;20547:23;20542:2;20538;20534:11;20530:41;20527:67;;;20574:18;;:::i;:::-;-1:-1:-1;;;20614:13:1;;;;;19935:698;-1:-1:-1;;;;;19935:698:1:o;20638:398::-;20677:4;20722:1;20718:2;20707:17;20759:1;20755:2;20744:17;20789:1;20784:3;20780:11;20873:3;-1:-1:-1;;;;;20832:39:1;20828:49;20823:3;20819:59;20814:2;20807:10;20803:76;20800:102;;;20882:18;;:::i;:::-;20971:3;-1:-1:-1;;;;;20931:44:1;20926:3;20922:54;20918:2;20914:63;20911:89;;;20980:18;;:::i;:::-;-1:-1:-1;21017:13:1;;;20638:398;-1:-1:-1;;;20638:398:1:o;21041:396::-;21080:3;21124:1;21120:2;21109:17;21161:1;21157:2;21146:17;21191:1;21186:3;21182:11;21270:3;-1:-1:-1;;;;;21230:44:1;21225:3;21221:54;21216:2;21209:10;21205:71;21202:97;;;21279:18;;:::i;:::-;21373:3;-1:-1:-1;;;;;21332:39:1;21328:49;21323:3;21319:59;21315:2;21311:68;21308:94;;;21382:18;;:::i;:::-;-1:-1:-1;21418:13:1;;21041:396;-1:-1:-1;;;21041:396:1:o;21803:267::-;21842:4;21871:9;;;21896:10;;-1:-1:-1;;;21915:19:1;;21908:27;;21892:44;21889:70;;;21939:18;;:::i;:::-;-1:-1:-1;;;;;21986:27:1;;21979:35;;21971:44;;21968:70;;;22018:18;;:::i;:::-;-1:-1:-1;;22055:9:1;;21803:267::o;22482:127::-;22543:10;22538:3;22534:20;22531:1;22524:31;22574:4;22571:1;22564:15;22598:4;22595:1;22588:15;22994:557;23238:25;;;23294:2;23279:18;;23272:34;;;23225:3;23210:19;;23336:1;23325:13;;23315:144;;23381:10;23376:3;23372:20;23369:1;23362:31;23416:4;23413:1;23406:15;23444:4;23441:1;23434:15;23315:144;23490:2;23475:18;;23468:34;;;;23533:2;23518:18;23511:34;22994:557;;-1:-1:-1;;22994:557:1:o;23556:228::-;23595:3;23623:10;23660:2;23657:1;23653:10;23690:2;23687:1;23683:10;23721:3;23717:2;23713:12;23708:3;23705:21;23702:47;;;23729:18;;:::i;:::-;23765:13;;23556:228;-1:-1:-1;;;;23556:228:1:o;23789:399::-;23991:2;23973:21;;;24030:2;24010:18;;;24003:30;24069:34;24064:2;24049:18;;24042:62;-1:-1:-1;;;24135:2:1;24120:18;;24113:33;24178:3;24163:19;;23789:399::o

Swarm Source

ipfs://536afad48d87d79f11e5d3fc4a9bd0a225d7d0ec8ed2f78d750d0312fa7a332b
[ 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.