Token veFBA

 

Overview ERC-721

Total Supply:
259,986.410481 veFBA

Holders:
60 addresses

Transfers:
-

Loading
[ Download CSV Export  ] 
Loading
[ Download CSV Export  ] 
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
ve

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 999999 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

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

// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

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

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

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * 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);
}

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

// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

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

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

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

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

// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

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

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

/// [MIT License]
/// @title Base64
/// @notice Provides a function for encoding some bytes in base64
/// @author Brecht Devos <[email protected]>
library Base64 {
    bytes internal constant TABLE =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /// @notice Encodes some bytes to the base64 representation
    function encode(bytes memory data) internal pure returns (string memory) {
        uint256 len = data.length;
        if (len == 0) return "";

        // multiply by 4/3 rounded up
        uint256 encodedLen = 4 * ((len + 2) / 3);

        // Add some extra buffer at the end
        bytes memory result = new bytes(encodedLen + 32);

        bytes memory table = TABLE;

        assembly {
            let tablePtr := add(table, 1)
            let resultPtr := add(result, 32)

            for {
                let i := 0
            } lt(i, len) {

            } {
                i := add(i, 3)
                let input := and(mload(add(data, i)), 0xffffff)

                let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))
                out := shl(8, out)
                out := add(
                    out,
                    and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)
                )
                out := shl(8, out)
                out := add(
                    out,
                    and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)
                )
                out := shl(8, out)
                out := add(
                    out,
                    and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)
                )
                out := shl(224, out)

                mstore(resultPtr, out)

                resultPtr := add(resultPtr, 4)
            }

            switch mod(len, 3)
            case 1 {
                mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
            }
            case 2 {
                mstore(sub(resultPtr, 1), shl(248, 0x3d))
            }

            mstore(result, encodedLen)
        }

        return string(result);
    }
}

interface IveListener {
    /**
     * @dev When a token weight is updated, this function is called if the contract is registered as observer.
     */
    function onTokenWeightUpdated(uint256 _tokenId) external;
}

interface ICappedMintableBurnableERC20 {
    function cap() external view returns (uint256);

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

    function mint(address, uint256) external;

    function burn(uint256) external;
}

/**
@title Voting Escrow
@author Curve Finance
@license MIT
@notice Votes have a weight depending on time, so that users are
committed to the future of (whatever they are voting for)
@dev Vote weight decays linearly over time. Lock time cannot be
more than `MAXTIME` (42 weeks).

# Voting escrow to have time-weighted votes
# Votes have a weight depending on time, so that users are committed
# to the future of (whatever they are voting for).
# The weight in this implementation is linear, and lock cannot be more than maxtime:
# w ^
# 1 +        /
#   |      /
#   |    /
#   |  /
#   |/
# 0 +--------+------> time
#       maxtime (42 weeks?)
*/
struct Point {
    int128 bias;
    int128 slope; // # -dweight / dt
    uint256 ts;
    uint256 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 */
struct LockedBalance {
    int128 amount;
    uint256 end;
}

contract ve is IERC721, IERC721Metadata, Ownable {
    enum DepositType {
        DEPOSIT_FOR_TYPE,
        CREATE_LOCK_TYPE,
        INCREASE_LOCK_AMOUNT,
        INCREASE_UNLOCK_TIME,
        MERGE_TYPE
    }

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

    uint256 internal constant WEEK = 1 weeks;
    uint256 public constant MAXTIME = 42 weeks;
    int128 internal constant iMAXTIME = 42 weeks;
    uint256 internal constant MULTIPLIER = 1 ether;

    address public immutable token;
    uint256 public supply;
    mapping(uint256 => LockedBalance) public locked;

    mapping(uint256 => uint256) public ownership_change;

    uint256 public epoch;
    mapping(uint256 => Point) public point_history; // epoch -> unsigned point
    mapping(uint256 => Point[1000000000]) public user_point_history; // user -> Point[user_epoch]

    mapping(uint256 => uint256) public user_point_epoch;
    mapping(uint256 => int128) public slope_changes; // time -> signed slope change

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

    address public voter;
    address public boardroom;
    address[] public listeners;

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

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

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

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

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

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

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

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

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

    uint256 public minLockedAmount = 1 ether;
    uint256 public earlyWithdrawFeeRate = 5000;

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

    modifier onlyVoter() {
        require(msg.sender == voter, "!voter");
        _;
    }

    /// @notice Contract constructor
    /// @param token_addr `ERC20_FBA` token address
    constructor(address token_addr) {
        token = token_addr;
        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);
    }

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

    /// @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(uint256 _tokenId)
        external
        view
        returns (int128)
    {
        uint256 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(uint256 _tokenId, uint256 _idx)
        external
        view
        returns (uint256)
    {
        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(uint256 _tokenId) external view returns (uint256) {
        return locked[_tokenId].end;
    }

    /// @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 (uint256) {
        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 (uint256) {
        return _balance(_owner);
    }

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

    /// @dev Get the approved address for a single NFT.
    /// @param _tokenId ID of the NFT to query the approval of.
    function getApproved(uint256 _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];
    }

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

    /// @dev  Get all tokens of an owner
    function allTokensOfOwner(address _owner)
        external
        view
        returns (uint256[] memory _tokenIds)
    {
        uint256 _length = ownerToNFTokenCount[_owner];
        _tokenIds = new uint256[](_length);
        for (uint256 _tokenIndex = 0; _tokenIndex < _length; _tokenIndex++) {
            _tokenIds[_tokenIndex] = ownerToNFTokenIdList[_owner][_tokenIndex];
        }
    }

    /// @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, uint256 _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, uint256 _tokenId)
        external
        view
        returns (bool)
    {
        return _isApprovedOrOwner(_spender, _tokenId);
    }

    /// @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, uint256 _tokenId) internal {
        uint256 current_count = _balance(_to);

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

    /// @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, uint256 _tokenId)
        internal
    {
        // Delete
        uint256 current_count = _balance(_from) - 1;
        uint256 current_index = tokenToOwnerIndex[_tokenId];

        if (current_count == current_index) {
            // update ownerToNFTokenIdList
            ownerToNFTokenIdList[_from][current_count] = 0;
            // update tokenToOwnerIndex
            tokenToOwnerIndex[_tokenId] = 0;
        } else {
            uint256 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 Add a NFT to a given address
    ///      Throws if `_tokenId` is owned by someone.
    function _addTokenTo(address _to, uint256 _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 Remove a NFT from a given address
    ///      Throws if `_from` is not the current owner.
    function _removeTokenFrom(address _from, uint256 _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;
    }

    /// @dev Clear an approval of a given address
    ///      Throws if `_owner` is not the current owner.
    function _clearApproval(address _owner, uint256 _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 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,
        uint256 _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);
        // 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);
    }

    /* TRANSFER FUNCTIONS */
    /// @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,
        uint256 _tokenId
    ) external {
        _transferFrom(_from, _to, _tokenId, msg.sender);
    }

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

    /// @dev 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,
        uint256 _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) {} catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert(
                        "ERC721: transfer to non ERC721Receiver implementer"
                    );
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /// @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,
        uint256 _tokenId
    ) external {
        safeTransferFrom(_from, _to, _tokenId, "");
    }

    /// @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, uint256 _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);
    }

    /// @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, uint256 _tokenId) internal returns (bool) {
        // Throws if `_to` is zero address
        assert(_to != address(0));
        // Add NFT. Throws if `_tokenId` is owned by someone
        _addTokenTo(_to, _tokenId);
        emit Transfer(address(0), _to, _tokenId);
        return true;
    }

    /// @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(
        uint256 _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;
        uint256 _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];
        }
        uint256 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;
        uint256 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
        {
            uint256 t_i = (last_checkpoint / WEEK) * WEEK;
            for (uint256 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
            uint256 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(
        uint256 _tokenId,
        uint256 _value,
        uint256 unlock_time,
        LockedBalance memory locked_balance,
        DepositType deposit_type
    ) internal {
        require(
            _value == 0 || _value >= minLockedAmount,
            "less than min amount"
        );

        LockedBalance memory _locked = locked_balance;
        uint256 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);

        uint256 _length = listeners.length;
        for (uint256 i = 0; i < _length; i++) {
            IveListener(listeners[i]).onTokenWeightUpdated(_tokenId);
        }
    }

    function setMinLockedAmount(uint256 _minLockedAmount) external onlyOwner {
        minLockedAmount = _minLockedAmount;
    }

    function setEarlyWithdrawFeeRate(uint256 _earlyWithdrawFeeRate)
        external
        onlyOwner
    {
        require(_earlyWithdrawFeeRate <= 10000, "too high"); // <= 100%
        earlyWithdrawFeeRate = _earlyWithdrawFeeRate;
    }

    function setVoter(address _voter) external onlyOwner {
        voter = _voter;
    }

    function setBoardroom(address _boardroom) external onlyOwner {
        boardroom = _boardroom;
    }

    function addListener(address _listener) external onlyOwner {
        listeners.push(_listener);
    }

    function setListeners(address[] calldata _listeners) external onlyOwner {
        delete listeners;
        uint256 _length = _listeners.length;
        for (uint256 i = 0; i < _length; i++) {
            listeners.push(_listeners[i]);
        }
    }

    function voting(uint256 _tokenId) external onlyVoter {
        voted[_tokenId] = true;
    }

    function abstain(uint256 _tokenId) external onlyVoter {
        voted[_tokenId] = false;
    }

    function attach(uint256 _tokenId) external onlyVoter {
        attachments[_tokenId] = attachments[_tokenId] + 1;
    }

    function detach(uint256 _tokenId) external onlyVoter {
        attachments[_tokenId] = attachments[_tokenId] - 1;
    }

    function merge(uint256 _from, uint256 _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];
        uint256 value0 = uint256(int256(_locked0.amount));
        uint256 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);
    }

    function block_number() external view returns (uint256) {
        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(uint256 _tokenId, uint256 _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(
        uint256 _value,
        uint256 _lock_duration,
        address _to
    ) internal returns (uint256) {
        uint256 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 42 weeks max"
        );

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

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

    /// @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(
        uint256 _value,
        uint256 _lock_duration,
        address _to
    ) external nonreentrant returns (uint256) {
        return _create_lock(_value, _lock_duration, _to);
    }

    /// @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(uint256 _value, uint256 _lock_duration)
        external
        nonreentrant
        returns (uint256)
    {
        return _create_lock(_value, _lock_duration, msg.sender);
    }

    /// @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(uint256 _tokenId, uint256 _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(uint256 _tokenId, uint256 _lock_duration)
        external
        nonreentrant
    {
        assert(_isApprovedOrOwner(msg.sender, _tokenId));

        LockedBalance memory _locked = locked[_tokenId];
        uint256 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 42 weeks 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(uint256 _tokenId) external nonreentrant {
        _withdraw(_tokenId, false);
    }

    // This will charge PENALTY if lock is not expired yet
    function emergencyWithdraw(uint256 _tokenId) external nonreentrant {
        _withdraw(_tokenId, true);
    }

    function _withdraw(uint256 _tokenId, bool _isEmergency) internal {
        assert(_isApprovedOrOwner(msg.sender, _tokenId));
        require(attachments[_tokenId] == 0 && !voted[_tokenId], "attached");

        LockedBalance memory _locked = locked[_tokenId];
        require(
            _isEmergency || block.timestamp >= _locked.end,
            "lock not expired"
        );
        uint256 value = uint256(int256(_locked.amount));

        locked[_tokenId] = LockedBalance(0, 0);
        uint256 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));

        if (_isEmergency) {
            uint256 _fee = (value * earlyWithdrawFeeRate) / 10000;
            ICappedMintableBurnableERC20(token).burn(_fee);
            assert(IERC20(token).transfer(msg.sender, value - _fee));
        } else {
            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);
    }

    // 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(uint256 _block, uint256 max_epoch)
        internal
        view
        returns (uint256)
    {
        // Binary search
        uint256 _min = 0;
        uint256 _max = max_epoch;
        for (uint256 i = 0; i < 128; ++i) {
            // Will be always enough for 128-bit numbers
            if (_min >= _max) {
                break;
            }
            uint256 _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(uint256 _tokenId, uint256 _t)
        internal
        view
        returns (uint256)
    {
        uint256 _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 uint256(int256(last_point.bias));
        }
    }

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

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

    function balanceOfNFTAt(uint256 _tokenId, uint256 _t)
        external
        view
        returns (uint256)
    {
        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(uint256 _tokenId, uint256 _block)
        internal
        view
        returns (uint256)
    {
        // Copying and pasting totalSupply code because Vyper cannot pass by
        // reference yet
        assert(_block <= block.number);

        // Binary search
        uint256 _min = 0;
        uint256 _max = user_point_epoch[_tokenId];
        for (uint256 i = 0; i < 128; ++i) {
            // Will be always enough for 128-bit numbers
            if (_min >= _max) {
                break;
            }
            uint256 _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];

        uint256 max_epoch = epoch;
        uint256 _epoch = _find_block_epoch(_block, max_epoch);
        Point memory point_0 = point_history[_epoch];
        uint256 d_block = 0;
        uint256 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;
        }
        uint256 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 uint256(uint128(upoint.bias));
        } else {
            return 0;
        }
    }

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

    /// @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, uint256 t)
        internal
        view
        returns (uint256)
    {
        Point memory last_point = point;
        uint256 t_i = (last_point.ts / WEEK) * WEEK;
        for (uint256 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 uint256(uint128(last_point.bias));
    }

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

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

    function tokenLength() external view returns (uint256) {
        return tokenId;
    }

    /// @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(uint256 _block) external view returns (uint256) {
        assert(_block <= block.number);
        uint256 _epoch = epoch;
        uint256 target_epoch = _find_block_epoch(_block, _epoch);

        Point memory point = point_history[target_epoch];
        uint256 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);
    }

    function _tokenURI(
        uint256 _tokenId,
        uint256 _balanceOf,
        uint256 _locked_end,
        uint256 _value
    ) internal pure returns (string memory output) {
        output = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">';
        output = string(
            abi.encodePacked(
                output,
                "token ",
                toString(_tokenId),
                '</text><text x="10" y="40" class="base">'
            )
        );
        output = string(
            abi.encodePacked(
                output,
                "balanceOf ",
                toString(_balanceOf),
                '</text><text x="10" y="60" class="base">'
            )
        );
        output = string(
            abi.encodePacked(
                output,
                "locked_end ",
                toString(_locked_end),
                '</text><text x="10" y="80" class="base">'
            )
        );
        output = string(
            abi.encodePacked(
                output,
                "value ",
                toString(_value),
                "</text></svg>"
            )
        );

        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        '{"name": "lock #',
                        toString(_tokenId),
                        '", "description": "Firebird Aggregator locks, can be used to vote on token emission, and receive sharing profits", "image": "data:image/svg+xml;base64,',
                        Base64.encode(bytes(output)),
                        '"}'
                    )
                )
            )
        );
        output = string(
            abi.encodePacked("data:application/json;base64,", json)
        );
    }

    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT license
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

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

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

        address owner = ownerOf(_tokenId);

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

    /* ========== EMERGENCY ========== */

    function governanceRecoverUnsupported(IERC20 _token) external onlyOwner {
        _token.transfer(owner(), _token.balanceOf(address(this)));
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"token_addr","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":"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 ve.DepositType","name":"deposit_type","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"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":"MAXTIME","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":"_listener","type":"address"}],"name":"addListener","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"allTokensOfOwner","outputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_approved","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","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":"boardroom","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","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":"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":"earlyWithdrawFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"emergencyWithdraw","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":"_tokenId","type":"uint256"}],"name":"get_last_user_slope","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"}],"name":"governanceRecoverUnsupported","outputs":[],"stateMutability":"nonpayable","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":"listeners","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"minLockedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_boardroom","type":"address"}],"name":"setBoardroom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_earlyWithdrawFeeRate","type":"uint256"}],"name":"setEarlyWithdrawFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_listeners","type":"address[]"}],"name":"setListeners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minLockedAmount","type":"uint256"}],"name":"setMinLockedAmount","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":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","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"}]

60a0604052670de0b6b3a76400006016556113886017556018805460ff191660011790553480156200003057600080fd5b5060405162005922380380620059228339810160408190526200005391620001dc565b6200005e336200018c565b6001600160a01b038116608052437f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746be55427f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bd5560156020527f6d41d7311dcf06e9efee8fb0d881f048bb31170f670666b54beaa0a5d5c3d3e1805460ff1990811660019081179092557f7c5380ac03aab70890fa83320849084ec294a4b2992171b171b58ecee9fd28868054821683179055635b5e139f60e01b60009081527f57deef6d7eb0781ed7c6a908946a1ec625e2f9c98c7ba2b9a5beae2409ad583780549092169092179055600e546040519091309160008051602062005902833981519152908290a4600e54604051600090309060008051602062005902833981519152908390a4506200020e565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215620001ef57600080fd5b81516001600160a01b03811681146200020757600080fd5b9392505050565b6080516156bc6200024660003960008181610b9d015281816129fb01528181612a6e01528181612b90015261358401526156bc6000f3fe608060405234801561001057600080fd5b50600436106104575760003560e01c80638da5cb5b11610250578063d08a12ff11610150578063e8d4a0f3116100c8578063f2fde38b11610097578063fbd3a29d1161007c578063fbd3a29d14610b85578063fc0c546a14610b98578063fd4a77f114610bbf57600080fd5b8063f2fde38b14610b4f578063f8a0576314610b6257600080fd5b8063e8d4a0f314610ad5578063e985e9c514610ae8578063ee00ef3a14610b31578063ee99fe2814610b3c57600080fd5b8063d5b502521161011f578063e0514aba11610104578063e0514aba14610a8f578063e441135c14610aa2578063e7e242d414610ac257600080fd5b8063d5b5025214610a74578063de66341e14610a8757600080fd5b8063d08a12ff146109f0578063d1c2babb14610a03578063d1febfb914610a16578063d4e54c3b14610a6157600080fd5b8063a25b39b7116101e3578063b45a3c0e116101b2578063c1f0fb9f11610197578063c1f0fb9f146109c2578063c2c4c5c1146109d5578063c87b56dd146109dd57600080fd5b8063b45a3c0e14610967578063b88d4fde146109af57600080fd5b8063a25b39b714610925578063a4d855df1461092e578063b1f3b35c14610941578063b3ffc7771461095457600080fd5b8063981b24d01161021f578063981b24d0146108d9578063986b7d8a146108ec578063a183af52146108ff578063a22cb4651461091257600080fd5b80638da5cb5b1461088f5780638fbb38ff146108ad578063900cf0cf146108d057806395d89b41146104e257600080fd5b806342842e0e1161035b5780635e02c51e116102ee57806370a08231116102bd57806371197484116102a25780637119748414610851578063715018a6146108745780638c2c9baf1461087c57600080fd5b806370a082311461082b5780637116c60c1461083e57600080fd5b80635e02c51e146107a25780636352211e146107c257806365fc3873146107f85780636f5488371461080b57600080fd5b80634842ff741161032a5780634842ff74146107375780634bc2a657146107405780635312ea8e1461075357806354fd4d501461076657600080fd5b806342842e0e146106cb578063430c2081146106de578063461f711c146106f157806346c96aac1461071757600080fd5b80631376f3da116103ee57806325a58b56116103bd5780632f745c59116103a25780632f745c591461064e578063313ce567146106915780633c99e2e9146106ab57600080fd5b806325a58b56146106355780632e1a7d4d1461063b57600080fd5b80631376f3da146105cc57806318160ddd146106075780631c984bc31461060f57806323b872dd1461062257600080fd5b8063081812fc1161042a578063081812fc1461052b578063095ea7b3146105865780630d12d97b146105995780630d6a2033146105ac57600080fd5b806301ffc9a71461045c578063047fc9aa146104b657806306b865b4146104cd57806306fdde03146104e2575b600080fd5b6104a161046a366004614807565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081526015602052604090205460ff1690565b60405190151581526020015b60405180910390f35b6104bf60015481565b6040519081526020016104ad565b6104e06104db366004614824565b610bd2565b005b61051e6040518060400160405280600581526020017f766546424100000000000000000000000000000000000000000000000000000081525081565b6040516104ad919061490f565b610561610539366004614922565b60009081526010602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016104ad565b6104e061059436600461495d565b610c8a565b6104e06105a7366004614922565b610dcb565b6104bf6105ba366004614922565b60096020526000908152604090205481565b6105df6105da366004614989565b610e49565b60408051600f95860b81529390940b60208401529282015260608101919091526080016104ad565b6104bf610e9d565b6104bf61061d366004614989565b610ead565b6104e06106303660046149ab565b610ee0565b436104bf565b6104e0610649366004614922565b610ef1565b6104bf61065c36600461495d565b73ffffffffffffffffffffffffffffffffffffffff919091166000908152601260209081526040808320938352929052205490565b610699601281565b60405160ff90911681526020016104ad565b6106be6106b93660046149ec565b610f67565b6040516104ad9190614a09565b6104e06106d93660046149ab565b611049565b6104a16106ec36600461495d565b611064565b6107046106ff366004614922565b611077565b604051600f9190910b81526020016104ad565b600b546105619073ffffffffffffffffffffffffffffffffffffffff1681565b6104bf60175481565b6104e061074e3660046149ec565b6110c7565b6104e0610761366004614922565b611116565b61051e6040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b600c546105619073ffffffffffffffffffffffffffffffffffffffff1681565b6105616107d0366004614922565b6000908152600f602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6104bf610806366004614989565b61115e565b6104bf610819366004614922565b60036020526000908152604090205481565b6104bf6108393660046149ec565b6111dc565b6104bf61084c366004614922565b611207565b61070461085f366004614922565b600860205260009081526040902054600f0b81565b6104e0611274565b6104bf61088a366004614989565b611288565b60005473ffffffffffffffffffffffffffffffffffffffff16610561565b6104a16108bb366004614922565b600a6020526000908152604090205460ff1681565b6104bf60045481565b6104bf6108e7366004614922565b611294565b6104e06108fa366004614922565b611450565b6104e061090d366004614989565b6114fe565b6104e0610920366004614a5b565b6116c9565b6104bf60165481565b6104e061093c366004614989565b611785565b61056161094f366004614922565b611a2b565b6104e06109623660046149ec565b611a62565b610995610975366004614922565b60026020526000908152604090208054600190910154600f9190910b9082565b60408051600f9390930b83526020830191909152016104ad565b6104e06109bd366004614ac3565b611ab1565b6104e06109d0366004614922565b611c49565b6104e0611d00565b61051e6109eb366004614922565b611d3e565b6104e06109fe366004614922565b611e12565b6104e0610a11366004614989565b611e1f565b6105df610a24366004614922565b600560205260009081526040902080546001820154600290920154600f82810b93700100000000000000000000000000000000909304900b919084565b6104bf610a6f366004614bc1565b611ff7565b6104e0610a823660046149ec565b612076565b600e546104bf565b6104bf610a9d366004614989565b6120f5565b6104bf610ab0366004614922565b60076020526000908152604090205481565b6104bf610ad0366004614922565b612101565b6104e0610ae33660046149ec565b612129565b6104a1610af6366004614bfa565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260146020908152604080832093909416825291909152205460ff1690565b6104bf630183990081565b6104e0610b4a366004614989565b612292565b6104e0610b5d3660046149ec565b612418565b6104bf610b70366004614922565b60009081526002602052604090206001015490565b6104e0610b93366004614922565b6124cf565b6105617f000000000000000000000000000000000000000000000000000000000000000081565b6104e0610bcd366004614922565b61256a565b610bda612624565b610be6600d60006147a7565b8060005b81811015610c8457600d848483818110610c0657610c06614c28565b9050602002016020810190610c1b91906149ec565b81546001810183556000928352602090922090910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905580610c7c81614c86565b915050610bea565b50505050565b6000818152600f602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610cb957600080fd5b8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610cf157600080fd5b6000828152600f602090815260408083205473ffffffffffffffffffffffffffffffffffffffff85811685526014845282852033808752945291909320549216149060ff168180610d3f5750805b610d4857600080fd5b60008481526010602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff89811691821790925591518793918716917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a45050505050565b610dd3612624565b612710811115610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f746f6f206869676800000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b601755565b600660205281600052604060002081633b9aca008110610e6857600080fd5b6003020180546001820154600290920154600f82810b955070010000000000000000000000000000000090920490910b925084565b6000610ea842611207565b905090565b600082815260066020526040812082633b9aca008110610ecf57610ecf614c28565b600302016001015490505b92915050565b610eec838383336126a5565b505050565b60185460ff16600114610f0357600080fd5b601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166002179055610f398160006127c2565b50601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601160205260409020546060908067ffffffffffffffff811115610fa957610fa9614a94565b604051908082528060200260200182016040528015610fd2578160200160208202803683370190505b50915060005b818110156110425773ffffffffffffffffffffffffffffffffffffffff84166000908152601260209081526040808320848452909152902054835184908390811061102557611025614c28565b60209081029190910101528061103a81614c86565b915050610fd8565b5050919050565b610eec83838360405180602001604052806000815250611ab1565b60006110708383612cb4565b9392505050565b6000818152600760209081526040808320546006909252822081633b9aca0081106110a4576110a4614c28565b60030201547001000000000000000000000000000000009004600f0b9392505050565b6110cf612624565b600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60185460ff1660011461112857600080fd5b601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166002179055610f398160016127c2565b60185460009060ff1660011461117357600080fd5b601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021790556111a9838333612d27565b9050601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905592915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260116020526040812054610eda565b600454600081815260056020908152604080832081516080810183528154600f81810b8352700100000000000000000000000000000000909104900b9381019390935260018101549183019190915260020154606082015290919061126c8185612ec9565b949350505050565b61127c612624565b6112866000612fd3565b565b60006110708383613048565b6000438211156112a6576112a6614cbe565b60045460006112b58483613351565b600081815260056020908152604080832081516080810183528154600f81810b8352700100000000000000000000000000000000909104900b93810193909352600181015491830191909152600201546060820152919250838310156113de576000600581611325866001614ced565b8152602080820192909252604090810160002081516080810183528154600f81810b8352700100000000000000000000000000000000909104900b93810193909352600181015491830191909152600201546060808301829052850151919250146113d8578260600151816060015161139e9190614d05565b836040015182604001516113b29190614d05565b60608501516113c1908a614d05565b6113cb9190614d1c565b6113d59190614d88565b91505b5061142d565b4382606001511461142d5760608201516113f89043614d05565b60408301516114079042614d05565b60608401516114169089614d05565b6114209190614d1c565b61142a9190614d88565b90505b611446828284604001516114419190614ced565b612ec9565b9695505050505050565b600b5473ffffffffffffffffffffffffffffffffffffffff1633146114d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f21766f74657200000000000000000000000000000000000000000000000000006044820152606401610e3b565b6000818152600960205260409020546114ec90600190614d05565b60009182526009602052604090912055565b60185460ff1660011461151057600080fd5b601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021790556115453383612cb4565b61155157611551614cbe565b60008281526002602090815260409182902082518084019093528054600f0b835260010154908201528161158757611587614cbe565b60008160000151600f0b136115f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006044820152606401610e3b565b4281602001511161168a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e205769746860448201527f64726177000000000000000000000000000000000000000000000000000000006064820152608401610e3b565b611699838360008460026133d7565b5050601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b3373ffffffffffffffffffffffffffffffffffffffff8316036116ee576116ee614cbe565b33600081815260146020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60185460ff1660011461179757600080fd5b601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021790556117cc3383612cb4565b6117d8576117d8614cbe565b600082815260026020908152604080832081518083019092528054600f0b825260010154918101919091529062093a80806118138542614ced565b61181d9190614d88565b6118279190614d1c565b905042826020015111611896576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4c6f636b206578706972656400000000000000000000000000000000000000006044820152606401610e3b565b60008260000151600f0b13611907576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e6f7468696e67206973206c6f636b65640000000000000000000000000000006044820152606401610e3b565b81602001518111611974576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006044820152606401610e3b565b611982630183990042614ced565b8111156119eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f566f74696e67206c6f636b2063616e206265203432207765656b73206d6178006044820152606401610e3b565b6119fa846000838560036133d7565b5050601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555050565b600d8181548110611a3b57600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b611a6a612624565b600c80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611abd848484336126a5565b823b15610c84576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84169063150b7a0290611b1c903390889087908790600401614d9c565b6020604051808303816000875af1925050508015611b75575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611b7291810190614ddb565b60015b611c42573d808015611ba3576040519150601f19603f3d011682016040523d82523d6000602084013e611ba8565b606091505b508051600003611c3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610e3b565b805181602001fd5b5050505050565b600b5473ffffffffffffffffffffffffffffffffffffffff163314611cca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f21766f74657200000000000000000000000000000000000000000000000000006044820152606401610e3b565b6000908152600a6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b611286600060405180604001604052806000600f0b8152602001600081525060405180604001604052806000600f0b81526020016000815250613768565b6000818152600f602052604090205460609073ffffffffffffffffffffffffffffffffffffffff16611dcc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f517565727920666f72206e6f6e6578697374656e7420746f6b656e00000000006044820152606401610e3b565b60008281526002602090815260409182902082518084019093528054600f0b8352600101549082015261107083611e038142613e15565b60208401518451600f0b613ef6565b611e1a612624565b601655565b600082815260096020526040902054158015611e4a57506000828152600a602052604090205460ff16155b611eb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f61747461636865640000000000000000000000000000000000000000000000006044820152606401610e3b565b808203611ebc57600080fd5b611ec63383612cb4565b611ecf57600080fd5b611ed93382612cb4565b611ee257600080fd5b6000828152600260208181526040808420815180830183528154600f90810b825260019283015482860190815288885295855283872084518086019095528054820b855290920154938301849052805194519095929490910b921115611f4c578260200151611f52565b83602001515b604080518082018252600080825260208083018281528b835260028252848320935184547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff90911617845551600190930192909255825180840190935280835290820152909150611fd89087908690613768565b611fe18661402d565b611fef8583838660046133d7565b505050505050565b60185460009060ff1660011461200c57600080fd5b601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166002179055612042848484612d27565b9050601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790559392505050565b61207e612624565b600d80546001810182556000919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60006110708383613e15565b60008181526003602052604081205443900361211f57506000919050565b610eda8242613e15565b612131612624565b8073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61216c60005473ffffffffffffffffffffffffffffffffffffffff1690565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa1580156121d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fa9190614df8565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af115801561226a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228e9190614e11565b5050565b60185460ff166001146122a457600080fd5b601880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660029081179091556000838152602091825260409081902081518083019092528054600f0b825260010154918101919091528161230657600080fd5b60008160000151600f0b13612377576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006044820152606401610e3b565b42816020015111612409576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e205769746860448201527f64726177000000000000000000000000000000000000000000000000000000006064820152608401610e3b565b611699838360008460006133d7565b612420612624565b73ffffffffffffffffffffffffffffffffffffffff81166124c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610e3b565b6124cc81612fd3565b50565b600b5473ffffffffffffffffffffffffffffffffffffffff163314612550576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f21766f74657200000000000000000000000000000000000000000000000000006044820152606401610e3b565b6000818152600960205260409020546114ec906001614ced565b600b5473ffffffffffffffffffffffffffffffffffffffff1633146125eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f21766f74657200000000000000000000000000000000000000000000000000006044820152606401610e3b565b6000908152600a6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314611286576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610e3b565b6000828152600960205260409020541580156126d057506000828152600a602052604090205460ff16155b612736576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f61747461636865640000000000000000000000000000000000000000000000006044820152606401610e3b565b6127408183612cb4565b61274957600080fd5b6127538483614120565b61275d84836141b7565b612767838361426a565b60008281526003602052604080822043905551839173ffffffffffffffffffffffffffffffffffffffff80871692908816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050565b6127cc3383612cb4565b6127d8576127d8614cbe565b60008281526009602052604090205415801561280357506000828152600a602052604090205460ff16155b612869576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f61747461636865640000000000000000000000000000000000000000000000006044820152606401610e3b565b60008281526002602090815260409182902082518084019093528054600f0b8352600101549082015281806128a2575080602001514210155b612908576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6c6f636b206e6f742065787069726564000000000000000000000000000000006044820152606401610e3b565b8051604080518082018252600080825260208083018281528883526002909152929020905181547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff909116178155905160019182015554600f9190910b906129828282614d05565b60015560408051808201909152600080825260208201526129a69086908590613768565b8315612b5b576000612710601754846129bf9190614d1c565b6129c99190614d88565b6040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906342966c6890602401600060405180830381600087803b158015612a5457600080fd5b505af1158015612a68573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb338386612ab59190614d05565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af1158015612b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b499190614e11565b612b5557612b55614cbe565b50612c1e565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015612bee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c129190614e11565b612c1e57612c1e614cbe565b612c278561402d565b60408051868152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c81612c958482614d05565b6040805192835260208301919091520160405180910390a15050505050565b6000818152600f6020908152604080832054601083528184205473ffffffffffffffffffffffffffffffffffffffff9182168086526014855283862088841680885295529285205492938085149392909116149060ff168280612d145750815b80612d1c5750805b979650505050505050565b60008062093a8080612d398642614ced565b612d439190614d88565b612d4d9190614d1c565b905060008511612d5c57600080fd5b428111612deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e207468652060448201527f66757475726500000000000000000000000000000000000000000000000000006064820152608401610e3b565b612df9630183990042614ced565b811115612e62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f566f74696e67206c6f636b2063616e206265203432207765656b73206d6178006044820152606401610e3b565b600e60008154612e7190614c86565b90915550600e54612e828482614332565b5060008181526002602090815260409182902082518084019093528054600f0b835260019081015491830191909152612ec0918391899186916133d7565b95945050505050565b600080839050600062093a80808360400151612ee59190614d88565b612eef9190614d1c565b905060005b60ff811015612fa257612f0a62093a8083614ced565b9150600085831115612f1e57859250612f32565b50600082815260086020526040902054600f0b5b6040840151612f419084614d05565b8460200151612f509190614e2e565b84518590612f5f908390614ee4565b600f0b905250858303612f725750612fa2565b8084602001818151612f849190614f55565b600f0b9052505060408301829052612f9b81614c86565b9050612ef4565b5060008260000151600f0b1215612fb857600082525b50516fffffffffffffffffffffffffffffffff169392505050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60004382111561305a5761305a614cbe565b600083815260076020526040812054815b60808110156130fa57818310156130fa576000600261308a8486614ced565b613095906001614ced565b61309f9190614d88565b6000888152600660205260409020909150869082633b9aca0081106130c6576130c6614c28565b6003020160020154116130db578093506130e9565b6130e6600182614d05565b92505b506130f381614c86565b905061306b565b50600085815260066020526040812083633b9aca00811061311d5761311d614c28565b60408051608081018252600392909202929092018054600f81810b8452700100000000000000000000000000000000909104900b60208301526001810154928201929092526002909101546060820152600454909150600061317f8783613351565b600081815260056020908152604080832081516080810183528154600f81810b8352700100000000000000000000000000000000909104900b9381019390935260018101549183019190915260020154606082015291925080848410156132785760006005816131f0876001614ced565b8152602080820192909252604090810160002081516080810183528154600f81810b8352700100000000000000000000000000000000909104900b9381019390935260018101549183019190915260020154606080830182905286015191925061325a9190614d05565b9250836040015181604001516132709190614d05565b91505061329c565b60608301516132879043614d05565b91508260400151426132999190614d05565b90505b604083015182156132d9578284606001518c6132b89190614d05565b6132c29084614d1c565b6132cc9190614d88565b6132d69082614ced565b90505b60408701516132e89082614d05565b87602001516132f79190614e2e565b87518890613306908390614ee4565b600f90810b90915288516000910b12905061333f57505093516fffffffffffffffffffffffffffffffff169650610eda95505050505050565b60009950505050505050505050610eda565b60008082815b60808110156133cd57818310156133cd57600060026133768486614ced565b613381906001614ced565b61338b9190614d88565b60008181526005602052604090206002015490915087106133ae578093506133bc565b6133b9600182614d05565b92505b506133c681614c86565b9050613357565b5090949350505050565b8315806133e657506016548410155b61344c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6c657373207468616e206d696e20616d6f756e740000000000000000000000006044820152606401610e3b565b600154829061345b8682614ced565b6001556040805180820190915260008082526020820152825160208085015190830152600f0b8152825187908490613494908390614f55565b600f0b90525085156134a857602083018690525b6000888152600260209081526040909120845181547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff9091161781559084015160019091015561350b888285613768565b33871580159061352d5750600485600481111561352a5761352a614fc5565b14155b156135fd576040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152306024830152604482018a90527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af11580156135cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f19190614e11565b6135fd576135fd614cbe565b83602001518173ffffffffffffffffffffffffffffffffffffffff167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248b8b894260405161364e9493929190614ff4565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c836136828a82614ced565b6040805192835260208301919091520160405180910390a1600d5460005b8181101561375b57600d81815481106136bb576136bb614c28565b6000918252602090912001546040517fb02e0f25000000000000000000000000000000000000000000000000000000008152600481018d905273ffffffffffffffffffffffffffffffffffffffff9091169063b02e0f2590602401600060405180830381600087803b15801561373057600080fd5b505af1158015613744573d6000803e3d6000fd5b50505050808061375390614c86565b9150506136a0565b5050505050505050505050565b604080516080810182526000808252602082018190529181018290526060810191909152604080516080810182526000808252602082018190529181018290526060810191909152600454600090819087156138d3574287602001511180156137d8575060008760000151600f0b135b1561381d5786516137ee9063018399009061504b565b600f0b602080870191909152870151613808904290614d05565b85602001516138179190614e2e565b600f0b85525b428660200151118015613837575060008660000151600f0b135b1561387c57855161384d9063018399009061504b565b600f0b602080860191909152860151613867904290614d05565b84602001516138769190614e2e565b600f0b84525b602080880151600090815260088252604090205490870151600f9190910b9350156138d35786602001518660200151036138b8578291506138d3565b602080870151600090815260089091526040902054600f0b91505b604080516080810182526000808252602082015242918101919091524360608201528115613955575060008181526005602090815260409182902082516080810184528154600f81810b8352700100000000000000000000000000000000909104900b9281019290925260018101549282019290925260029091015460608201525b6040810151816000428310156139a25760408401516139749042614d05565b60608501516139839043614d05565b61399590670de0b6b3a7640000614d1c565b61399f9190614d88565b90505b600062093a806139b28186614d88565b6139bc9190614d1c565b905060005b60ff811015613b4c576139d762093a8083614ced565b91506000428311156139eb574292506139ff565b50600082815260086020526040902054600f0b5b613a098684614d05565b8760200151613a189190614e2e565b87518890613a27908390614ee4565b600f0b905250602087018051829190613a41908390614f55565b600f90810b90915288516000910b12159050613a5c57600087525b60008760200151600f0b1215613a7457600060208801525b60408088018490528501519295508592670de0b6b3a764000090613a989085614d05565b613aa29086614d1c565b613aac9190614d88565b8560600151613abb9190614ced565b6060880152613acb600189614ced565b9750428303613ae05750436060870152613b4c565b6000888152600560209081526040918290208951918a01516fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000029216919091178155908801516001820155606088015160029091015550613b4581614c86565b90506139c1565b505060048590558b15613bd75788602001518860200151613b6d9190614ee4565b84602001818151613b7e9190614f55565b600f0b90525088518851613b929190614ee4565b84518590613ba1908390614f55565b600f90810b90915260208601516000910b12159050613bc257600060208501525b60008460000151600f0b1215613bd757600084525b6000858152600560209081526040918290208651918701516fffffffffffffffffffffffffffffffff90811670010000000000000000000000000000000002921691909117815590850151600182015560608501516002909101558b15613e0757428b602001511115613cc5576020890151613c539088614f55565b96508a602001518a6020015103613c76576020880151613c739088614ee4565b96505b60208b810151600090815260089091526040902080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff89161790555b428a602001511115613d41578a602001518a602001511115613d41576020880151613cf09087614ee4565b60208b810151600090815260089091526040902080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff831617905595505b60008c815260076020526040812054613d5b906001614ced565b905080600760008f815260200190815260200160002081905550428960400181815250504389606001818152505088600660008f815260200190815260200160002082633b9aca008110613db157613db1614c28565b825160208401516fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000029116176003919091029190910190815560408201516001820155606090910151600290910155505b505050505050505050505050565b600082815260076020526040812054808203613e35576000915050610eda565b600084815260066020526040812082633b9aca008110613e5757613e57614c28565b60408051608081018252600392909202929092018054600f81810b8452700100000000000000000000000000000000909104900b602083015260018101549282018390526002015460608201529150613eb090856150bf565b8160200151613ebf9190614e2e565b81518290613ece908390614ee4565b600f90810b90915282516000910b12159050613ee957600081525b51600f0b9150610eda9050565b606060405180610120016040528060fd815260200161554a60fd9139905080613f1e866143af565b604051602001613f2f929190615133565b604051602081830303815290604052905080613f4a856143af565b604051602001613f5b9291906151db565b604051602081830303815290604052905080613f76846143af565b604051602001613f87929190615283565b604051602081830303815290604052905080613fa2836143af565b604051602001613fb392919061532b565b60405160208183030381529060405290506000614000613fd2876143af565b613fdb846144e4565b604051602001613fec9291906153ad565b6040516020818303038152906040526144e4565b90508060405160200161401391906154f0565b604051602081830303815290604052915050949350505050565b6140373382612cb4565b61409d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f7665646044820152606401610e3b565b6000818152600f602052604081205473ffffffffffffffffffffffffffffffffffffffff16906140cd9083610c8a565b6140d733836141b7565b604051829060009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000818152600f602052604090205473ffffffffffffffffffffffffffffffffffffffff83811691161461415657614156614cbe565b60008181526010602052604090205473ffffffffffffffffffffffffffffffffffffffff161561228e57600090815260106020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b6000818152600f602052604090205473ffffffffffffffffffffffffffffffffffffffff8381169116146141ed576141ed614cbe565b6000818152600f6020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561422b82826146c1565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601160205260408120805460019290614261908490614d05565b90915550505050565b6000818152600f602052604090205473ffffffffffffffffffffffffffffffffffffffff161561429c5761429c614cbe565b6000818152600f6020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716908117909155808452601180845282852080546012865284872081885286528487208890558787526013865293862093909355908452909152805460019290614261908490614ced565b600073ffffffffffffffffffffffffffffffffffffffff831661435757614357614cbe565b614361838361426a565b604051829073ffffffffffffffffffffffffffffffffffffffff8516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a450600192915050565b6060816000036143f257505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561441c578061440681614c86565b91506144159050600a83614d88565b91506143f6565b60008167ffffffffffffffff81111561443757614437614a94565b6040519080825280601f01601f191660200182016040528015614461576020820181803683370190505b5090505b841561126c57614476600183614d05565b9150614483600a86615535565b61448e906030614ced565b60f81b8183815181106144a3576144a3614c28565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506144dd600a86614d88565b9450614465565b80516060906000819003614508575050604080516020810190915260008152919050565b60006003614517836002614ced565b6145219190614d88565b61452c906004614d1c565b9050600061453b826020614ced565b67ffffffffffffffff81111561455357614553614a94565b6040519080825280601f01601f19166020018201604052801561457d576020820181803683370190505b5090506000604051806060016040528060408152602001615647604091399050600181016020830160005b86811015614609576003818a01810151603f601282901c8116860151600c83901c8216870151600684901c831688015192909316870151600891821b60ff94851601821b92841692909201901b91160160e01b8352600490920191016145a8565b506003860660018114614623576002811461466d576146b3565b7f3d3d0000000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8301526146b3565b7f3d000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8301525b505050918152949350505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601160205260408120546146f390600190614d05565b60008381526013602052604090205490915080820361474f5773ffffffffffffffffffffffffffffffffffffffff8416600090815260126020908152604080832085845282528083208390558583526013909152812055610c84565b73ffffffffffffffffffffffffffffffffffffffff9390931660009081526012602090815260408083209383529281528282208054868452848420819055835260139091528282209490945592839055908252812055565b50805460008255906000526020600020908101906124cc91905b808211156147d557600081556001016147c1565b5090565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146124cc57600080fd5b60006020828403121561481957600080fd5b8135611070816147d9565b6000806020838503121561483757600080fd5b823567ffffffffffffffff8082111561484f57600080fd5b818501915085601f83011261486357600080fd5b81358181111561487257600080fd5b8660208260051b850101111561488757600080fd5b60209290920196919550909350505050565b60005b838110156148b457818101518382015260200161489c565b83811115610c845750506000910152565b600081518084526148dd816020860160208601614899565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061107060208301846148c5565b60006020828403121561493457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146124cc57600080fd5b6000806040838503121561497057600080fd5b823561497b8161493b565b946020939093013593505050565b6000806040838503121561499c57600080fd5b50508035926020909101359150565b6000806000606084860312156149c057600080fd5b83356149cb8161493b565b925060208401356149db8161493b565b929592945050506040919091013590565b6000602082840312156149fe57600080fd5b81356110708161493b565b6020808252825182820181905260009190848201906040850190845b81811015614a4157835183529284019291840191600101614a25565b50909695505050505050565b80151581146124cc57600080fd5b60008060408385031215614a6e57600080fd5b8235614a798161493b565b91506020830135614a8981614a4d565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060008060808587031215614ad957600080fd5b8435614ae48161493b565b93506020850135614af48161493b565b925060408501359150606085013567ffffffffffffffff80821115614b1857600080fd5b818701915087601f830112614b2c57600080fd5b813581811115614b3e57614b3e614a94565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715614b8457614b84614a94565b816040528281528a6020848701011115614b9d57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600080600060608486031215614bd657600080fd5b83359250602084013591506040840135614bef8161493b565b809150509250925092565b60008060408385031215614c0d57600080fd5b8235614c188161493b565b91506020830135614a898161493b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614cb757614cb7614c57565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60008219821115614d0057614d00614c57565b500190565b600082821015614d1757614d17614c57565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614d5457614d54614c57565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614d9757614d97614d59565b500490565b600073ffffffffffffffffffffffffffffffffffffffff80871683528086166020840152508360408301526080606083015261144660808301846148c5565b600060208284031215614ded57600080fd5b8151611070816147d9565b600060208284031215614e0a57600080fd5b5051919050565b600060208284031215614e2357600080fd5b815161107081614a4d565b600081600f0b83600f0b6f7fffffffffffffffffffffffffffffff600082136000841383830485118282161615614e6757614e67614c57565b7fffffffffffffffffffffffffffffffff800000000000000000000000000000006000851286820586128184161615614ea257614ea2614c57565b60008712925085820587128484161615614ebe57614ebe614c57565b85850587128184161615614ed457614ed4614c57565b5050509290910295945050505050565b600081600f0b83600f0b60008112817fffffffffffffffffffffffffffffffff8000000000000000000000000000000001831281151615614f2757614f27614c57565b816f7fffffffffffffffffffffffffffffff018313811615614f4b57614f4b614c57565b5090039392505050565b600081600f0b83600f0b60008212826f7fffffffffffffffffffffffffffffff03821381151615614f8857614f88614c57565b827fffffffffffffffffffffffffffffffff80000000000000000000000000000000038212811615614fbc57614fbc614c57565b50019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b848152602081018490526080810160058410615039577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60408201939093526060015292915050565b600081600f0b83600f0b8061506257615062614d59565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffff80000000000000000000000000000000831416156150b6576150b6614c57565b90059392505050565b6000808312837f8000000000000000000000000000000000000000000000000000000000000000018312811516156150f9576150f9614c57565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01831381161561512d5761512d614c57565b50500390565b60008351615145818460208801614899565b7f746f6b656e200000000000000000000000000000000000000000000000000000908301908152835161517f816006840160208801614899565b7f3c2f746578743e3c7465787420783d2231302220793d2234302220636c617373600692909101918201527f3d2262617365223e0000000000000000000000000000000000000000000000006026820152602e01949350505050565b600083516151ed818460208801614899565b7f62616c616e63654f662000000000000000000000000000000000000000000000908301908152835161522781600a840160208801614899565b7f3c2f746578743e3c7465787420783d2231302220793d2236302220636c617373600a92909101918201527f3d2262617365223e000000000000000000000000000000000000000000000000602a820152603201949350505050565b60008351615295818460208801614899565b7f6c6f636b65645f656e642000000000000000000000000000000000000000000090830190815283516152cf81600b840160208801614899565b7f3c2f746578743e3c7465787420783d2231302220793d2238302220636c617373600b92909101918201527f3d2262617365223e000000000000000000000000000000000000000000000000602b820152603301949350505050565b6000835161533d818460208801614899565b7f76616c75652000000000000000000000000000000000000000000000000000009083019081528351615377816006840160208801614899565b7f3c2f746578743e3c2f7376673e0000000000000000000000000000000000000060069290910191820152601301949350505050565b7f7b226e616d65223a20226c6f636b2023000000000000000000000000000000008152600083516153e5816010850160208801614899565b7f222c20226465736372697074696f6e223a2022466972656269726420416767726010918401918201527f656761746f72206c6f636b732c2063616e206265207573656420746f20766f7460308201527f65206f6e20746f6b656e20656d697373696f6e2c20616e64207265636569766560508201527f2073686172696e672070726f66697473222c2022696d616765223a202264617460708201527f613a696d6167652f7376672b786d6c3b6261736536342c000000000000000000609082015283516154ba8160a7840160208801614899565b7f227d00000000000000000000000000000000000000000000000000000000000060a7929091019182015260a901949350505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161552881601d850160208701614899565b91909101601d0192915050565b60008261554457615544614d59565b50069056fe3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f73766722207072657365727665417370656374526174696f3d22784d696e594d696e206d656574222076696577426f783d223020302033353020333530223e3c7374796c653e2e62617365207b2066696c6c3a2077686974653b20666f6e742d66616d696c793a2073657269663b20666f6e742d73697a653a20313470783b207d3c2f7374796c653e3c726563742077696474683d223130302522206865696768743d2231303025222066696c6c3d22626c61636b22202f3e3c7465787420783d2231302220793d2232302220636c6173733d2262617365223e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220ce2d56e9b552f4223adf6e5046fec4fed9a2ebe35db4e3f404955e97d0b4014a64736f6c634300080f0033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef0000000000000000000000000e249130b3545a2a287de9f27d805cab95f03db9

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

0000000000000000000000000e249130b3545a2a287de9f27d805cab95f03db9

-----Decoded View---------------
Arg [0] : token_addr (address): 0x0e249130b3545a2a287de9f27d805cab95f03db9

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000e249130b3545a2a287de9f27d805cab95f03db9


Deployed ByteCode Sourcemap

17502:48894:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21848:168;;;;;;:::i;:::-;21975:33;;21946:4;21975:33;;;:19;:33;;;;;;;;;21848:168;;;;611:14:1;;604:22;586:41;;574:2;559:18;21848:168:0;;;;;;;;18360:21;;;;;;;;;784:25:1;;;772:2;757:18;18360:21:0;638:177:1;46593:257:0;;;;;;:::i;:::-;;:::i;:::-;;19049:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;24162:120::-;;;;;;:::i;:::-;24224:7;24251:23;;;:13;:23;;;;;;;;;24162:120;;;;2611:42:1;2599:55;;;2581:74;;2569:2;2554:18;24162:120:0;2435:226:1;35165:661:0;;;;;;:::i;:::-;;:::i;46028:242::-;;;;;;:::i;:::-;;:::i;18857:46::-;;;;;;:::i;:::-;;;;;;;;;;;;;;18611:63;;;;;;:::i;:::-;;:::i;:::-;;;;3654:2:1;3643:22;;;3625:41;;3702:22;;;;3697:2;3682:18;;3675:50;3741:18;;;3734:34;3799:2;3784:18;;3777:34;;;;3612:3;3597:19;18611:63:0;3398:419:1;61593:112:0;;;:::i;22634:191::-;;;;;;:::i;:::-;;:::i;31327:177::-;;;;;;:::i;:::-;;:::i;48093:94::-;48167:12;48093:94;;53300:103;;;;;;:::i;:::-;;:::i;24718:197::-;;;;;;:::i;:::-;24866:28;;;;;24834:7;24866:28;;;:20;:28;;;;;;;;:41;;;;;;;;;24718:197;19186:35;;19219:2;19186:35;;;;;4455:4:1;4443:17;;;4425:36;;4413:2;4398:18;19186:35:0;4283:184:1;24965:405:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;34433:176::-;;;;;;:::i;:::-;;:::i;26181:188::-;;;;;;:::i;:::-;;:::i;22195:232::-;;;;;;:::i;:::-;;:::i;:::-;;;5534:2:1;5523:22;;;;5505:41;;5493:2;5478:18;22195:232:0;5361:191:1;18956:20:0;;;;;;;;;20636:42;;;;;;46278:86;;;;;;:::i;:::-;;:::i;53471:111::-;;;;;;:::i;:::-;;:::i;19139:40::-;;;;;;;;;;;;;;;;;;;;;18983:24;;;;;;;;;23922:110;;;;;;:::i;:::-;23978:7;24005:19;;;:9;:19;;;;;;;;;23922:110;51135:207;;;;;;:::i;:::-;;:::i;18444:51::-;;;;;;:::i;:::-;;;;;;;;;;;;;;23694:109;;;;;;:::i;:::-;;:::i;61378:207::-;;;;;;:::i;:::-;;:::i;18770:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;12948:103;;;:::i;59894:181::-;;;;;;:::i;:::-;;:::i;12300:87::-;12346:7;12373:6;;;12300:87;;18910:37;;;;;;:::i;:::-;;;;;;;;;;;;;;;;18504:20;;;;;;61997:979;;;;;;:::i;:::-;;:::i;47193:121::-;;;;;;:::i;:::-;;:::i;51522:645::-;;;;;;:::i;:::-;;:::i;36338:301::-;;;;;;:::i;:::-;;:::i;20589:40::-;;;;;;52303:885;;;;;;:::i;:::-;;:::i;19014:26::-;;;;;;:::i;:::-;;:::i;46372:102::-;;;;;;:::i;:::-;;:::i;18388:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6268:2:1;6257:22;;;;6239:41;;6311:2;6296:18;;6289:34;;;;6212:18;18388:47:0;6067:262:1;32716:986:0;;;;;;:::i;:::-;;:::i;46960:96::-;;;;;;:::i;:::-;;:::i;48245:106::-;;;:::i;56941:482::-;;;;;;:::i;:::-;;:::i;45894:126::-;;;;;;:::i;:::-;;:::i;47322:763::-;;;;;;:::i;:::-;;:::i;18531:46::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50680:219;;;;;;:::i;:::-;;:::i;46482:103::-;;;;;;:::i;:::-;;:::i;61713:88::-;61786:7;;61713:88;;57644:171;;;;;;:::i;:::-;;:::i;18712:51::-;;;;;;:::i;:::-;;;;;;;;;;;;;;57431:205;;;;;;:::i;:::-;;:::i;66245:148::-;;;;;;:::i;:::-;;:::i;24491:185::-;;;;;;:::i;:::-;24632:24;;;;24602:4;24632:24;;;:16;:24;;;;;;;;24631:37;;;;;;;;;;;;;;;24491:185;18168:42;;18202:8;18168:42;;48676:575;;;;;;:::i;:::-;;:::i;13206:238::-;;;;;;:::i;:::-;;:::i;22974:117::-;;;;;;:::i;:::-;23036:7;23063:16;;;:6;:16;;;;;:20;;;;22974:117;47064:121;;;;;;:::i;:::-;;:::i;18323:30::-;;;;;46858:94;;;;;;:::i;:::-;;:::i;46593:257::-;12186:13;:11;:13::i;:::-;46676:16:::1;46683:9;;46676:16;:::i;:::-;46721:10:::0;46703:15:::1;46749:94;46773:7;46769:1;:11;46749:94;;;46802:9;46817:10;;46828:1;46817:13;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;46802:29:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;46802:29:0;;;::::1;::::0;;;;;::::1;::::0;;;::::1;;::::0;;::::1;::::0;;;::::1;::::0;;46782:3;::::1;::::0;::::1;:::i;:::-;;;;46749:94;;;;46665:185;46593:257:::0;;:::o;35165:661::-;35237:13;35253:19;;;:9;:19;;;;;;;;;35335:28;;;;;;35450:5;35437:18;;:9;:18;;;35429:27;;;;;;35498:18;35520:19;;;:9;:19;;;;;;;;;:33;35596:23;;;;;:16;:23;;;;;35543:10;35595:37;;;;;;;;;;35520:19;;:33;;35595:37;;35520:33;;35651:39;;;35668:22;35651:39;35643:48;;;;;;35731:23;;;;:13;:23;;;;;;:35;;;;;;;;;;;;;;35782:36;;35731:23;;35782:36;;;;;;;35226:600;;;35165:661;;:::o;46028:242::-;12186:13;:11;:13::i;:::-;46178:5:::1;46153:21;:30;;46145:51;;;::::0;::::1;::::0;;9679:2:1;46145:51:0::1;::::0;::::1;9661:21:1::0;9718:1;9698:18;;;9691:29;9756:10;9736:18;;;9729:38;9784:18;;46145:51:0::1;;;;;;;;;46218:20;:44:::0;46028:242::o;18611:63::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;18611:63:0;;;;;;;;-1:-1:-1;18611:63:0;:::o;61593:112::-;61639:7;61666:31;61681:15;61666:14;:31::i;:::-;61659:38;;61593:112;:::o;22634:191::-;22748:7;22780:28;;;:18;:28;;;;;22809:4;22780:34;;;;;;;:::i;:::-;;;;:37;;;22773:44;;22634:191;;;;;:::o;31327:177::-;31449:47;31463:5;31470:3;31475:8;31485:10;31449:13;:47::i;:::-;31327:177;;;:::o;53300:103::-;20891:14;;:30;:14;20757:1;20891:30;20883:39;;;;;;20933:14;:25;;;;20800:1;20933:25;;;53369:26:::1;53379:8:::0;20933:14;53369:9:::1;:26::i;:::-;-1:-1:-1::0;20981:14:0;:29;;;;20757:1;20981:29;;;53300:103::o;24965:405::-;25119:27;;;25101:15;25119:27;;;:19;:27;;;;;;25057:26;;25119:27;25169:22;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;25169:22:0;;25157:34;;25207:19;25202:161;25246:7;25232:11;:21;25202:161;;;25310:28;;;;;;;:20;:28;;;;;;;;:41;;;;;;;;;25285:22;;:9;;25339:11;;25285:22;;;;;;:::i;:::-;;;;;;;;;;:66;25255:13;;;;:::i;:::-;;;;25202:161;;;;25090:280;24965:405;;;:::o;34433:176::-;34559:42;34576:5;34583:3;34588:8;34559:42;;;;;;;;;;;;:16;:42::i;26181:188::-;26294:4;26323:38;26342:8;26352;26323:18;:38::i;:::-;26316:45;26181:188;-1:-1:-1;;;26181:188:0:o;22195:232::-;22292:6;22333:26;;;:16;:26;;;;;;;;;22377:18;:28;;;;;22333:26;22377:36;;;;;;;:::i;:::-;;;;:42;;;;;;;22195:232;-1:-1:-1;;;22195:232:0:o;46278:86::-;12186:13;:11;:13::i;:::-;46342:5:::1;:14:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;46278:86::o;53471:111::-;20891:14;;:30;:14;20757:1;20891:30;20883:39;;;;;;20933:14;:25;;;;20800:1;20933:25;;;53549::::1;53559:8:::0;20933:25;53549:9:::1;:25::i;51135:207::-:0;20891:14;;51254:7;;20891:30;:14;20757:1;20891:30;20883:39;;;;;;20933:14;:25;;;;20800:1;20933:25;;;51286:48:::1;51299:6:::0;51307:14;51323:10:::1;51286:12;:48::i;:::-;51279:55;;20981:14:::0;:29;;;;20757:1;20981:29;;;51135:207;;-1:-1:-1;;51135:207:0:o;23694:109::-;23417:27;;;23752:7;23417:27;;;:19;:27;;;;;;23779:16;23333:119;61378:207;61471:5;;61434:7;61513:21;;;:13;:21;;;;;;;;61487:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61434:7;;61471:5;61552:25;61487:47;61575:1;61552:10;:25::i;:::-;61545:32;61378:207;-1:-1:-1;;;;61378:207:0:o;12948:103::-;12186:13;:11;:13::i;:::-;13013:30:::1;13040:1;13013:18;:30::i;:::-;12948:103::o:0;59894:181::-;60002:7;60034:33;60050:8;60060:6;60034:15;:33::i;61997:979::-;62059:7;62096:12;62086:6;:22;;62079:30;;;;:::i;:::-;62137:5;;62120:14;62176:33;62194:6;62137:5;62176:17;:33::i;:::-;62222:18;62243:27;;;:13;:27;;;;;;;;62222:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62153:56;;-1:-1:-1;62310:21:0;;;62306:549;;;62348:23;62374:13;62348:23;62388:16;:12;62403:1;62388:16;:::i;:::-;62374:31;;;;;;;;;;;;;;-1:-1:-1;62374:31:0;62348:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62424:9;;;62348:57;;-1:-1:-1;62424:27:0;62420:197;;62591:5;:9;;;62574:10;:14;;;:26;;;;:::i;:::-;62539:5;:8;;;62523:10;:13;;;:24;;;;:::i;:::-;62509:9;;;;62500:18;;:6;:18;:::i;:::-;62499:49;;;;:::i;:::-;62498:103;;;;:::i;:::-;62472:129;;62420:197;62333:295;62306:549;;;62666:12;62653:5;:9;;;:25;62649:195;;62818:9;;;;62803:24;;:12;:24;:::i;:::-;62768:8;;;;62750:26;;:15;:26;:::i;:::-;62736:9;;;;62727:18;;:6;:18;:::i;:::-;62726:51;;;;:::i;:::-;62725:103;;;;:::i;:::-;62699:129;;62649:195;62936:32;62947:5;62965:2;62954:5;:8;;;:13;;;;:::i;:::-;62936:10;:32::i;:::-;62929:39;61997:979;-1:-1:-1;;;;;;61997:979:0:o;47193:121::-;21080:5;;;;21066:10;:19;21058:38;;;;;;;11014:2:1;21058:38:0;;;10996:21:1;11053:1;11033:18;;;11026:29;11091:8;11071:18;;;11064:36;11117:18;;21058:38:0;10812:329:1;21058:38:0;47281:21:::1;::::0;;;:11:::1;:21;::::0;;;;;:25:::1;::::0;47305:1:::1;::::0;47281:25:::1;:::i;:::-;47257:21;::::0;;;:11:::1;:21;::::0;;;;;:49;47193:121::o;51522:645::-;20891:14;;:30;:14;20757:1;20891:30;20883:39;;;;;;20933:14;:25;;;;20800:1;20933:25;;;51644:40:::1;51663:10;51675:8:::0;51644:18:::1;:40::i;:::-;51637:48;;;;:::i;:::-;51698:28;51729:16:::0;;;:6:::1;:16;::::0;;;;;;;;51698:47;;;;::::1;::::0;;;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;51765:10;51758:18:::1;;;;:::i;:::-;51840:1;51823:7;:14;;;:18;;;51815:53;;;::::0;::::1;::::0;;11348:2:1;51815:53:0::1;::::0;::::1;11330:21:1::0;11387:2;11367:18;;;11360:30;11426:24;11406:18;;;11399:52;11468:18;;51815:53:0::1;11146:346:1::0;51815:53:0::1;51915:15;51901:7;:11;;;:29;51879:115;;;::::0;::::1;::::0;;11699:2:1;51879:115:0::1;::::0;::::1;11681:21:1::0;11738:2;11718:18;;;11711:30;11777:34;11757:18;;;11750:62;11848:6;11828:18;;;11821:34;11872:19;;51879:115:0::1;11497:400:1::0;51879:115:0::1;52007:152;52034:8;52057:6;52078:1;52094:7;52116:32;52007:12;:152::i;:::-;-1:-1:-1::0;;20981:14:0;:29;;;;20757:1;20981:29;;;-1:-1:-1;51522:645:0:o;36338:301::-;36494:10;36481:23;;;;36474:31;;;;:::i;:::-;36533:10;36516:28;;;;:16;:28;;;;;;;;;:39;;;;;;;;;;;;:51;;;;;;;;;;;;;36583:48;;586:41:1;;;36516:39:0;;36533:10;36583:48;;559:18:1;36583:48:0;;;;;;;36338:301;;:::o;52303:885::-;20891:14;;:30;:14;20757:1;20891:30;20883:39;;;;;;20933:14;:25;;;;20800:1;20933:25;;;52438:40:::1;52457:10;52469:8:::0;52438:18:::1;:40::i;:::-;52431:48;;;;:::i;:::-;52492:28;52523:16:::0;;;:6:::1;:16;::::0;;;;;;;52492:47;;;;::::1;::::0;;;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;;;;18154:7:::1;::::0;52574:32:::1;52592:14:::0;52574:15:::1;:32;:::i;:::-;52573:41;;;;:::i;:::-;52572:63;;;;:::i;:::-;52550:85;;52707:15;52693:7;:11;;;:29;52685:54;;;::::0;::::1;::::0;;12104:2:1;52685:54:0::1;::::0;::::1;12086:21:1::0;12143:2;12123:18;;;12116:30;12182:14;12162:18;;;12155:42;12214:18;;52685:54:0::1;11902:336:1::0;52685:54:0::1;52775:1;52758:7;:14;;;:18;;;52750:48;;;::::0;::::1;::::0;;12445:2:1;52750:48:0::1;::::0;::::1;12427:21:1::0;12484:2;12464:18;;;12457:30;12523:19;12503:18;;;12496:47;12560:18;;52750:48:0::1;12243:341:1::0;52750:48:0::1;52831:7;:11;;;52817;:25;52809:69;;;::::0;::::1;::::0;;12791:2:1;52809:69:0::1;::::0;::::1;12773:21:1::0;12830:2;12810:18;;;12803:30;12869:33;12849:18;;;12842:61;12920:18;;52809:69:0::1;12589:355:1::0;52809:69:0::1;52926:25;18202:8;52926:15;:25;:::i;:::-;52911:11;:40;;52889:121;;;::::0;::::1;::::0;;13151:2:1;52889:121:0::1;::::0;::::1;13133:21:1::0;13190:2;13170:18;;;13163:30;13229:33;13209:18;;;13202:61;13280:18;;52889:121:0::1;12949:355:1::0;52889:121:0::1;53023:157;53050:8;53073:1;53089:11;53115:7;53137:32;53023:12;:157::i;:::-;-1:-1:-1::0;;20981:14:0;:29;;;;20757:1;20981:29;;;-1:-1:-1;;52303:885:0:o;19014:26::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;19014:26:0;:::o;46372:102::-;12186:13;:11;:13::i;:::-;46444:9:::1;:22:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;46372:102::o;32716:986::-;32869:47;32883:5;32890:3;32895:8;32905:10;32869:13;:47::i;:::-;31834:20;;31882:8;32929:766;;33092:176;;;;;:37;;;;;;:176;;33152:10;;33185:5;;33213:8;;33244:5;;33092:176;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;33092:176:0;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;33071:613;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33353:6;:13;33370:1;33353:18;33349:320;;33396:108;;;;;14282:2:1;33396:108:0;;;14264:21:1;14321:2;14301:18;;;14294:30;14360:34;14340:18;;;14333:62;14431:20;14411:18;;;14404:48;14469:19;;33396:108:0;14080:414:1;33349:320:0;33619:6;33613:13;33604:6;33600:2;33596:15;33589:38;33071:613;33282:19;32716:986;;;;:::o;46960:96::-;21080:5;;;;21066:10;:19;21058:38;;;;;;;11014:2:1;21058:38:0;;;10996:21:1;11053:1;11033:18;;;11026:29;11091:8;11071:18;;;11064:36;11117:18;;21058:38:0;10812:329:1;21058:38:0;47043:5:::1;47025:15:::0;;;:5:::1;:15;::::0;;;;:23;;;::::1;::::0;;46960:96::o;48245:106::-;48287:56;48299:1;48302:19;;;;;;;;48316:1;48302:19;;;;;;48319:1;48302:19;;;48323;;;;;;;;48337:1;48323:19;;;;;;48340:1;48323:19;;;48287:11;:56::i;56941:482::-;57079:1;57048:19;;;:9;:19;;;;;;57000:13;;57048:33;:19;57026:110;;;;;;;14701:2:1;57026:110:0;;;14683:21:1;14740:2;14720:18;;;14713:30;14779:29;14759:18;;;14752:57;14826:18;;57026:110:0;14499:351:1;57026:110:0;57147:28;57178:16;;;:6;:16;;;;;;;;;57147:47;;;;;;;;;;;;;;;;;;;;;57225:190;57185:8;57280:40;57185:8;57304:15;57280:13;:40::i;:::-;57339:11;;;;57384:14;;57377:22;;57225:9;:190::i;45894:126::-;12186:13;:11;:13::i;:::-;45978:15:::1;:34:::0;45894:126::o;47322:763::-;47393:18;;;;:11;:18;;;;;;:23;:40;;;;-1:-1:-1;47421:12:0;;;;:5;:12;;;;;;;;47420:13;47393:40;47385:61;;;;;;;15057:2:1;47385:61:0;;;15039:21:1;15096:1;15076:18;;;15069:29;15134:10;15114:18;;;15107:38;15162:18;;47385:61:0;14855:331:1;47385:61:0;47474:3;47465:5;:12;47457:21;;;;;;47497:37;47516:10;47528:5;47497:18;:37::i;:::-;47489:46;;;;;;47554:35;47573:10;47585:3;47554:18;:35::i;:::-;47546:44;;;;;;47603:29;47635:13;;;:6;:13;;;;;;;;47603:45;;;;;;;;;;;;;;;;;;;;;;;;;;47691:11;;;;;;;;;47659:43;;;;;;;;;;;;;;;;;;;;;;;;47745:15;;47787:12;;47603:45;;47659:43;;47738:23;;;;-1:-1:-1;47787:28:0;:84;;47859:8;:12;;;47787:84;;;47831:8;:12;;;47787:84;47900:19;;;;;;;;-1:-1:-1;47900:19:0;;;;;;;;;;47884:13;;;:6;:13;;;;;:35;;;;;;;;;;;;;;-1:-1:-1;47884:35:0;;;;;;;47959:19;;;;;;;;;;;;;;;47773:98;;-1:-1:-1;47930:49:0;;47884:13;;47949:8;;47930:11;:49::i;:::-;47990:12;47996:5;47990;:12::i;:::-;48013:64;48026:3;48031:6;48039:3;48044:8;48054:22;48013:12;:64::i;:::-;47374:711;;;;47322:763;;:::o;50680:219::-;20891:14;;50823:7;;20891:30;:14;20757:1;20891:30;20883:39;;;;;;20933:14;:25;;;;20800:1;20933:25;;;50850:41:::1;50863:6:::0;50871:14;50887:3;50850:12:::1;:41::i;:::-;50843:48;;20981:14:::0;:29;;;;20757:1;20981:29;;;50680:219;;-1:-1:-1;;;50680:219:0:o;46482:103::-;12186:13;:11;:13::i;:::-;46552:9:::1;:25:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;46552:25:0;;;;;::::1;::::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;46482:103::o;57644:171::-;57748:7;57780:27;57794:8;57804:2;57780:13;:27::i;57431:205::-;57494:7;57518:26;;;:16;:26;;;;;;57548:12;57518:42;;57514:56;;-1:-1:-1;57569:1:0;;57431:205;-1:-1:-1;57431:205:0:o;57514:56::-;57588:40;57602:8;57612:15;57588:13;:40::i;66245:148::-;12186:13;:11;:13::i;:::-;66328:6:::1;:15;;;66344:7;12346::::0;12373:6;;;;12300:87;66344:7:::1;66353:31;::::0;;;;66378:4:::1;66353:31;::::0;::::1;2581:74:1::0;66353:16:0::1;::::0;::::1;::::0;::::1;::::0;2554:18:1;;66353:31:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66328:57;::::0;;::::1;::::0;;;;;;15584:42:1;15572:55;;;66328:57:0::1;::::0;::::1;15554:74:1::0;15644:18;;;15637:34;15527:18;;66328:57:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;66245:148:::0;:::o;48676:575::-;20891:14;;:30;:14;20757:1;20891:30;20883:39;;;;;;20933:14;:25;;;;20800:1;20933:25;;;;;;:14;48818:16;;;::::1;::::0;;;;;;;;48787:47;;;;::::1;::::0;;;;;::::1;;::::0;;20933:25;48787:47:::1;::::0;;;::::1;::::0;;;;48855:10;48847:19:::1;;;::::0;::::1;;48930:1;48913:7;:14;;;:18;;;48905:53;;;::::0;::::1;::::0;;11348:2:1;48905:53:0::1;::::0;::::1;11330:21:1::0;11387:2;11367:18;;;11360:30;11426:24;11406:18;;;11399:52;11468:18;;48905:53:0::1;11146:346:1::0;48905:53:0::1;49005:15;48991:7;:11;;;:29;48969:115;;;::::0;::::1;::::0;;11699:2:1;48969:115:0::1;::::0;::::1;11681:21:1::0;11738:2;11718:18;;;11711:30;11777:34;11757:18;;;11750:62;11848:6;11828:18;;;11821:34;11872:19;;48969:115:0::1;11497:400:1::0;48969:115:0::1;49095:148;49122:8;49145:6;49166:1;49182:7;49204:28;49095:12;:148::i;13206:238::-:0;12186:13;:11;:13::i;:::-;13309:22:::1;::::0;::::1;13287:110;;;::::0;::::1;::::0;;16134:2:1;13287:110:0::1;::::0;::::1;16116:21:1::0;16173:2;16153:18;;;16146:30;16212:34;16192:18;;;16185:62;16283:8;16263:18;;;16256:36;16309:19;;13287:110:0::1;15932:402:1::0;13287:110:0::1;13408:28;13427:8;13408:18;:28::i;:::-;13206:238:::0;:::o;47064:121::-;21080:5;;;;21066:10;:19;21058:38;;;;;;;11014:2:1;21058:38:0;;;10996:21:1;11053:1;11033:18;;;11026:29;11091:8;11071:18;;;11064:36;11117:18;;21058:38:0;10812:329:1;21058:38:0;47152:21:::1;::::0;;;:11:::1;:21;::::0;;;;;:25:::1;::::0;47176:1:::1;47152:25;:::i;46858:94::-:0;21080:5;;;;21066:10;:19;21058:38;;;;;;;11014:2:1;21058:38:0;;;10996:21:1;11053:1;11033:18;;;11026:29;11091:8;11071:18;;;11064:36;11117:18;;21058:38:0;10812:329:1;21058:38:0;46922:15:::1;::::0;;;:5:::1;:15;::::0;;;;:22;;;::::1;46940:4;46922:22;::::0;;46858:94::o;12465:132::-;12346:7;12373:6;12529:23;12373:6;10994:10;12529:23;12521:68;;;;;;;16541:2:1;12521:68:0;;;16523:21:1;;;16560:18;;;16553:30;16619:34;16599:18;;;16592:62;16671:18;;12521:68:0;16339:356:1;29925:792:0;30082:21;;;;:11;:21;;;;;;:26;:46;;;;-1:-1:-1;30113:15:0;;;;:5;:15;;;;;;;;30112:16;30082:46;30074:67;;;;;;;15057:2:1;30074:67:0;;;15039:21:1;15096:1;15076:18;;;15069:29;15134:10;15114:18;;;15107:38;15162:18;;30074:67:0;14855:331:1;30074:67:0;30191:37;30210:7;30219:8;30191:18;:37::i;:::-;30183:46;;;;;;30311:31;30326:5;30333:8;30311:14;:31::i;:::-;30417:33;30434:5;30441:8;30417:16;:33::i;:::-;30481:26;30493:3;30498:8;30481:11;:26::i;:::-;30593;;;;:16;:26;;;;;;30622:12;30593:41;;30679:30;30610:8;;30679:30;;;;;;;;;;;;29925:792;;;;:::o;53590:1302::-;53673:40;53692:10;53704:8;53673:18;:40::i;:::-;53666:48;;;;:::i;:::-;53733:21;;;;:11;:21;;;;;;:26;:46;;;;-1:-1:-1;53764:15:0;;;;:5;:15;;;;;;;;53763:16;53733:46;53725:67;;;;;;;15057:2:1;53725:67:0;;;15039:21:1;15096:1;15076:18;;;15069:29;15134:10;15114:18;;;15107:38;15162:18;;53725:67:0;14855:331:1;53725:67:0;53805:28;53836:16;;;:6;:16;;;;;;;;;53805:47;;;;;;;;;;;;;;;;;;;;;53885:12;;:46;;;53920:7;:11;;;53901:15;:30;;53885:46;53863:112;;;;;;;16902:2:1;53863:112:0;;;16884:21:1;16941:2;16921:18;;;16914:30;16980:18;16960;;;16953:46;17016:18;;53863:112:0;16700:340:1;53863:112:0;54017:14;;54065:19;;;;;;;;-1:-1:-1;54065:19:0;;;;;;;;;;54046:16;;;:6;:16;;;;;;:38;;;;;;;;;;;;;;;-1:-1:-1;54046:38:0;;;;54119:6;54010:22;;;;;;54145:21;54010:22;54119:6;54145:21;:::i;:::-;54136:6;:30;54355:19;;;;;;;;;-1:-1:-1;54355:19:0;;;;;;;54324:51;;54336:8;;54346:7;;54324:11;:51::i;:::-;54392:12;54388:312;;;54421:12;54469:5;54445:20;;54437:5;:28;;;;:::i;:::-;54436:38;;;;:::i;:::-;54489:46;;;;;;;;784:25:1;;;54421:53:0;;-1:-1:-1;54518:5:0;54489:40;;;;;757:18:1;;54489:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54564:5;54557:22;;;54580:10;54600:4;54592:5;:12;;;;:::i;:::-;54557:48;;;;;;;;;;15584:42:1;15572:55;;;54557:48:0;;;15554:74:1;15644:18;;;15637:34;15527:18;;54557:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;54550:56;;;;:::i;:::-;54406:212;54388:312;;;54646:41;;;;;54669:10;54646:41;;;15554:74:1;15644:18;;;15637:34;;;54653:5:0;54646:22;;;;;15527:18:1;;54646:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;54639:49;;;;:::i;:::-;54737:15;54743:8;54737:5;:15::i;:::-;54770:54;;;17247:25:1;;;17303:2;17288:18;;17281:34;;;54808:15:0;17331:18:1;;;17324:34;54770:54:0;;54779:10;;54770:54;;;;;;17235:2:1;54770:54:0;;;54840:44;54847:13;54862:21;54878:5;54847:13;54862:21;:::i;:::-;54840:44;;;17543:25:1;;;17599:2;17584:18;;17577:34;;;;17516:18;54840:44:0;;;;;;;53655:1237;;;53590:1302;;:::o;25716:457::-;25830:4;25868:19;;;:9;:19;;;;;;;;;25985:13;:23;;;;;;25868:19;;;;26051:23;;;:16;:23;;;;;25920:17;;;26050:35;;;;;;;;;25868:19;;25920:17;;;;25985:23;;;;25973:35;;26050;;25920:17;;26103:35;;;26121:17;26103:35;:62;;;;26142:23;26103:62;26096:69;25716:457;-1:-1:-1;;;;;;;25716:457:0:o;49519:893::-;49646:7;;18154;;49690:32;49708:14;49690:15;:32;:::i;:::-;49689:41;;;;:::i;:::-;49688:63;;;;:::i;:::-;49666:85;;49818:1;49809:6;:10;49801:19;;;;;;49895:15;49881:11;:29;49859:117;;;;;;;17824:2:1;49859:117:0;;;17806:21:1;17863:2;17843:18;;;17836:30;17902:34;17882:18;;;17875:62;17973:8;17953:18;;;17946:36;17999:19;;49859:117:0;17622:402:1;49859:117:0;50024:25;18202:8;50024:15;:25;:::i;:::-;50009:11;:40;;49987:121;;;;;;;13151:2:1;49987:121:0;;;13133:21:1;13190:2;13170:18;;;13163:30;13229:33;13209:18;;;13202:61;13280:18;;49987:121:0;12949:355:1;49987:121:0;50123:7;;50121:9;;;;;:::i;:::-;;;;-1:-1:-1;50160:7:0;;50178:20;50184:3;50160:7;50178:5;:20::i;:::-;-1:-1:-1;50308:16:0;;;;:6;:16;;;;;;;;;50211:167;;;;;;;;;;;;;;;;;;;;;;;;;;;;50238:8;;50261:6;;50282:11;;50211:12;:167::i;:::-;50396:8;49519:893;-1:-1:-1;;;;;49519:893:0:o;60332:872::-;60433:7;60458:23;60484:5;60458:31;;60500:11;18154:7;;60515:10;:13;;;:20;;;;:::i;:::-;60514:29;;;;:::i;:::-;60500:43;;60559:9;60554:509;60578:3;60574:1;:7;60554:509;;;60603:11;18154:7;60603:11;;:::i;:::-;;;60629:14;60672:1;60666:3;:7;60662:124;;;60700:1;60694:7;;60662:124;;;-1:-1:-1;60752:18:0;;;;:13;:18;;;;;;;;60662:124;60892:13;;;;60886:19;;:3;:19;:::i;:::-;60836:10;:16;;;:71;;;;:::i;:::-;60800:107;;:10;;:107;;;;;:::i;:::-;;;;;-1:-1:-1;60926:8:0;;;60922:54;;60955:5;;;60922:54;61010:7;60990:10;:16;;:27;;;;;;;:::i;:::-;;;;;-1:-1:-1;;61032:13:0;;;:19;;;60583:3;;;:::i;:::-;;;60554:509;;;;61097:1;61079:10;:15;;;:19;;;61075:71;;;61133:1;61115:19;;61075:71;-1:-1:-1;61179:15:0;61163:33;;;60332:872;-1:-1:-1;;;60332:872:0:o;13604:191::-;13678:16;13697:6;;;13714:17;;;;;;;;;;13747:40;;13697:6;;;;;;;13747:40;;13678:16;13747:40;13667:128;13604:191;:::o;58125:1761::-;58234:7;58380:12;58370:6;:22;;58363:30;;;;:::i;:::-;58432:12;58474:26;;;:16;:26;;;;;;58432:12;58511:397;58535:3;58531:1;:7;58511:397;;;58630:4;58622;:12;58618:58;58655:5;58618:58;58690:12;58725:1;58706:11;58713:4;58706;:11;:::i;:::-;:15;;58720:1;58706:15;:::i;:::-;58705:21;;;;:::i;:::-;58745:28;;;;:18;:28;;;;;58690:36;;-1:-1:-1;58787:6:0;;58690:36;58745:34;;;;;;;:::i;:::-;;;;:38;;;:48;58741:156;;58821:4;58814:11;;58741:156;;;58873:8;58880:1;58873:4;:8;:::i;:::-;58866:15;;58741:156;-1:-1:-1;58540:3:0;;;:::i;:::-;;;58511:397;;;-1:-1:-1;58920:19:0;58942:28;;;:18;:28;;;;;58971:4;58942:34;;;;;;;:::i;:::-;58920:56;;;;;;;;58942:34;;;;;;;;;58920:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59009:5;;58920:56;;-1:-1:-1;;59042:36:0;59060:6;59009:5;59042:17;:36::i;:::-;59089:20;59112:21;;;:13;:21;;;;;;;;59089:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59025:53;;-1:-1:-1;59089:20:0;59204:18;;;59200:311;;;59239:20;59262:13;59239:20;59276:10;:6;59285:1;59276:10;:::i;:::-;59262:25;;;;;;;;;;;;;;-1:-1:-1;59262:25:0;59239:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59326:11;;;59239:48;;-1:-1:-1;59312:25:0;;59326:11;59312:25;:::i;:::-;59302:35;;59371:7;:10;;;59358:7;:10;;;:23;;;;:::i;:::-;59352:29;;59224:169;59200:311;;;59439:11;;;;59424:26;;:12;:26;:::i;:::-;59414:36;;59489:7;:10;;;59471:15;:28;;;;:::i;:::-;59465:34;;59200:311;59542:10;;;;59567:12;;59563:99;;59643:7;59627;:11;;;59618:6;:20;;;;:::i;:::-;59611:28;;:3;:28;:::i;:::-;59610:40;;;;:::i;:::-;59596:54;;;;:::i;:::-;;;59563:99;59731:9;;;;59718:22;;:10;:22;:::i;:::-;59689:6;:12;;;:53;;;;:::i;:::-;59674:68;;:6;;:68;;;;;:::i;:::-;;;;;;;;59757:11;;59772:1;59757:16;;;;-1:-1:-1;59753:126:0;;-1:-1:-1;;59813:11:0;;59797:29;;;-1:-1:-1;59790:36:0;;-1:-1:-1;;;;;;59790:36:0;59753:126;59866:1;59859:8;;;;;;;;;;;;;55304:636;55416:7;;55509:9;55416:7;55529:382;55553:3;55549:1;:7;55529:382;;;55648:4;55640;:12;55636:58;55673:5;55636:58;55708:12;55743:1;55724:11;55731:4;55724;:11;:::i;:::-;:15;;55738:1;55724:15;:::i;:::-;55723:21;;;;:::i;:::-;55763:19;;;;:13;:19;;;;;:23;;;55708:36;;-1:-1:-1;55763:33:0;-1:-1:-1;55759:141:0;;55824:4;55817:11;;55759:141;;;55876:8;55883:1;55876:4;:8;:::i;:::-;55869:15;;55759:141;-1:-1:-1;55558:3:0;;;:::i;:::-;;;55529:382;;;-1:-1:-1;55928:4:0;;55304:636;-1:-1:-1;;;;55304:636:0:o;44127:1759::-;44361:11;;;:40;;;44386:15;;44376:6;:25;;44361:40;44339:110;;;;;;;19819:2:1;44339:110:0;;;19801:21:1;19858:2;19838:18;;;19831:30;19897:22;19877:18;;;19870:50;19937:18;;44339:110:0;19617:344:1;44339:110:0;44542:6;;44493:14;;44570:22;44586:6;44542;44570:22;:::i;:::-;44561:6;:31;-1:-1:-1;;;;;;;;;;;;;;;;;44684:14:0;;44700:11;;;;;44665:14;;;44645:67;;;;;44805:40;;44837:6;;44684:7;;44805:40;;44837:6;;44805:40;:::i;:::-;;;;;-1:-1:-1;44860:16:0;;44856:74;;44893:11;;;:25;;;44856:74;44940:16;;;;:6;:16;;;;;;;;:26;;;;;;;;;;;;;;;;;-1:-1:-1;44940:26:0;;;;45218:42;44940:16;45240:10;44940:26;45218:11;:42::i;:::-;45288:10;45313:11;;;;;:53;;-1:-1:-1;45344:22:0;45328:12;:38;;;;;;;;:::i;:::-;;;45313:53;45309:149;;;45390:55;;;;;:26;20436:15:1;;;45390:55:0;;;20418:34:1;45431:4:0;20468:18:1;;;20461:43;20520:18;;;20513:34;;;45397:5:0;45390:26;;;;20330:18:1;;45390:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;45383:63;;;;:::i;:::-;45560:7;:11;;;45497:4;45475:164;;;45516:8;45539:6;45586:12;45613:15;45475:164;;;;;;;;;:::i;:::-;;;;;;;;45655:45;45662:13;45677:22;45693:6;45662:13;45677:22;:::i;:::-;45655:45;;;17543:25:1;;;17599:2;17584:18;;17577:34;;;;17516:18;45655:45:0;;;;;;;45731:9;:16;45713:15;45758:121;45782:7;45778:1;:11;45758:121;;;45823:9;45833:1;45823:12;;;;;;;;:::i;:::-;;;;;;;;;;;45811:56;;;;;;;;784:25:1;;;45823:12:0;;;;;45811:46;;757:18:1;;45811:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45791:3;;;;;:::i;:::-;;;;45758:121;;;;44328:1558;;;;;44127:1759;;;;;:::o;37595:6189::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37893:5:0;;37812:17;;;;37915:13;;37911:1254;;38057:15;38040:10;:14;;;:32;:57;;;;;38096:1;38076:10;:17;;;:21;;;38040:57;38036:276;;;38132:17;;:28;;18253:8;;38132:28;:::i;:::-;38118:42;;:11;;;;:42;;;;38262:14;;;:32;;38279:15;;38262:32;:::i;:::-;38213:5;:11;;;:83;;;;:::i;:::-;38179:117;;;;38036:276;38347:15;38330:10;:14;;;:32;:57;;;;;38386:1;38366:10;:17;;;:21;;;38330:57;38326:276;;;38422:17;;:28;;18253:8;;38422:28;:::i;:::-;38408:42;;:11;;;;:42;;;;38552:14;;;:32;;38569:15;;38552:32;:::i;:::-;38503:5;:11;;;:83;;;;:::i;:::-;38469:117;;;;38326:276;38870:14;;;;;38856:29;;;;:13;:29;;;;;;38904:14;;;;38856:29;;;;;;-1:-1:-1;38904:19:0;38900:254;;38966:10;:14;;;38948:10;:14;;;:32;38944:195;;39018:10;39005:23;;38944:195;;;39104:14;;;;;39090:29;;;;:13;:29;;;;;;;;;;-1:-1:-1;38944:195:0;39203:129;;;;;;;;39177:23;39203:129;;;;;;;39273:15;39203:129;;;;;;;39308:12;39203:129;;;;39347:10;;39343:77;;-1:-1:-1;39387:21:0;;;;:13;:21;;;;;;;;;39374:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39343:77;39456:13;;;;:10;39430:23;39802:15;:31;-1:-1:-1;39798:194:0;;;39966:13;;;;39948:31;;:15;:31;:::i;:::-;39911:14;;;;39896:29;;:12;:29;:::i;:::-;39882:44;;18307:7;39882:44;:::i;:::-;39881:99;;;;:::i;:::-;39850:130;;39798:194;40231:11;18154:7;40246:22;18154:7;40246:15;:22;:::i;:::-;40245:31;;;;:::i;:::-;40231:45;;40296:9;40291:1491;40315:3;40311:1;:7;40291:1491;;;40521:11;18154:7;40521:11;;:::i;:::-;;;40551:14;40598:15;40592:3;:21;40588:168;;;40644:15;40638:21;;40588:168;;;-1:-1:-1;40718:18:0;;;;:13;:18;;;;;;;;40588:168;40868:21;40874:15;40868:3;:21;:::i;:::-;40814:10;:16;;;:77;;;;:::i;:::-;40774:117;;:10;;:117;;;;;:::i;:::-;;;;;-1:-1:-1;40910:16:0;;;:27;;40930:7;;40910:16;:27;;40930:7;;40910:27;:::i;:::-;;;;;;;;40960:15;;40978:1;40960:19;;;40956:127;;-1:-1:-1;40956:127:0;;41062:1;41044:19;;40956:127;41124:1;41105:10;:16;;;:20;;;41101:147;;;41227:1;41208:16;;;:20;41101:147;41306:13;;;;:19;;;41450:21;;;41284:3;;-1:-1:-1;41284:3:0;;18307:7;;41444:27;;41284:3;41444:27;:::i;:::-;41429:43;;:11;:43;:::i;:::-;41428:79;;;;:::i;:::-;41382:18;:22;;;:125;;;;:::i;:::-;41344:14;;;:163;41526:11;41536:1;41526:11;;:::i;:::-;;;41567:15;41560:3;:22;41556:211;;-1:-1:-1;41624:12:0;41607:14;;;:29;41659:5;;41556:211;41713:21;;;;:13;:21;;;;;;;;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;40320:3:0;;;:::i;:::-;;;40291:1491;;;-1:-1:-1;;41805:5:0;:14;;;41888:13;;41884:483;;42096:5;:11;;;42082:5;:11;;;:25;;;;:::i;:::-;42061:10;:16;;:47;;;;;;;:::i;:::-;;;;;-1:-1:-1;42156:10:0;;42143;;:23;;42156:10;42143:23;:::i;:::-;42123:44;;:10;;:44;;;;;:::i;:::-;;;;;;;;42186:16;;;;42205:1;42186:20;;;42182:81;;-1:-1:-1;42182:81:0;;42246:1;42227:16;;;:20;42182:81;42299:1;42281:10;:15;;;:19;;;42277:79;;;42339:1;42321:19;;42277:79;42429:21;;;;:13;:21;;;;;;;;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42480:13;;42476:1301;;42720:15;42703:10;:14;;;:32;42699:402;;;42850:11;;;;42836:25;;;;:::i;:::-;;;42902:10;:14;;;42884:10;:14;;;:32;42880:145;;42955:11;;;;42941:25;;;;:::i;:::-;;;42880:145;43057:14;;;;;43043:29;;;;:13;:29;;;;;;:42;;;;;;;;;;42699:402;43138:15;43121:10;:14;;;:32;43117:344;;;43195:10;:14;;;43178:10;:14;;;:31;43174:209;;;43248:11;;;;43234:25;;;;:::i;:::-;43335:14;;;;;43321:29;;;;:13;:29;;;;;;:42;;;;;;;;;;;-1:-1:-1;43174:209:0;43515:18;43536:26;;;:16;:26;;;;;;:30;;43565:1;43536:30;:::i;:::-;43515:51;;43612:10;43583:16;:26;43600:8;43583:26;;;;;;;;;;;:39;;;;43648:15;43637:5;:8;;:26;;;;;43690:12;43678:5;:9;;:24;;;;;43760:5;43717:18;:28;43736:8;43717:28;;;;;;;;;;;43746:10;43717:40;;;;;;;:::i;:::-;:48;;;;;;;;;;;;;;;:40;;;;;;;;;:48;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;42476:1301:0;37743:6041;;;;;;;;;37595:6189;;;:::o;56220:612::-;56323:7;56365:26;;;:16;:26;;;;;;56406:11;;;56402:423;;56441:1;56434:8;;;;;56402:423;56475:23;56501:28;;;:18;:28;;;;;56530:6;56501:36;;;;;;;:::i;:::-;56475:62;;;;;;;;56501:36;;;;;;;;;56475:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;56631:34:0;;56638:2;56631:34;:::i;:::-;56588:10;:16;;;:78;;;;:::i;:::-;56552:114;;:10;;:114;;;;;:::i;:::-;;;;;;;;56685:15;;56703:1;56685:19;;;56681:79;;-1:-1:-1;56681:79:0;;56743:1;56725:19;;56681:79;56796:15;56789:23;;;-1:-1:-1;56774:39:0;;-1:-1:-1;56774:39:0;62984:2044;63144:20;63177:264;;;;;;;;;;;;;;;;;;;63517:6;63569:18;63578:8;63569;:18::i;:::-;63482:181;;;;;;;;;:::i;:::-;;;;;;;;;;;;;63452:222;;63750:6;63806:20;63815:10;63806:8;:20::i;:::-;63715:187;;;;;;;;;:::i;:::-;;;;;;;;;;;;;63685:228;;63989:6;64046:21;64055:11;64046:8;:21::i;:::-;63954:189;;;;;;;;;:::i;:::-;;;;;;;;;;;;;63924:230;;64230:6;64282:16;64291:6;64282:8;:16::i;:::-;64195:152;;;;;;;;;:::i;:::-;;;;;;;;;;;;;64165:193;;64371:18;64392:521;64561:18;64570:8;64561;:18::i;:::-;64786:28;64806:6;64786:13;:28::i;:::-;64473:395;;;;;;;;;:::i;:::-;;;;;;;;;;;;;64392:13;:521::i;:::-;64371:542;;65004:4;64954:55;;;;;;;;:::i;:::-;;;;;;;;;;;;;64924:96;;63166:1862;62984:2044;;;;;;:::o;65767:425::-;65842:40;65861:10;65873:8;65842:18;:40::i;:::-;65820:122;;;;;;;27602:2:1;65820:122:0;;;27584:21:1;;;27621:18;;;27614:30;27680:34;27660:18;;;27653:62;27732:18;;65820:122:0;27400:356:1;65820:122:0;65955:13;24005:19;;;:9;:19;;;;;;;;;66028:29;;24005:19;66028:7;:29::i;:::-;66093:38;66110:10;66122:8;66093:16;:38::i;:::-;66147:37;;66175:8;;66171:1;;66147:37;;;;;;66171:1;;66147:37;65809:383;65767:425;:::o;29174:327::-;29315:19;;;;:9;:19;;;;;;:29;;;;:19;;:29;29308:37;;;;:::i;:::-;29395:1;29360:23;;;:13;:23;;;;;;:37;:23;:37;29356:138;;29480:1;29446:23;;;:13;:23;;;;;:36;;;;;;-1:-1:-1;29174:327:0:o;28631:425::-;28772:19;;;;:9;:19;;;;;;:28;;;;:19;;:28;28765:36;;;;:::i;:::-;28871:1;28841:19;;;:9;:19;;;;;:32;;;;;;28930:42;28956:5;28851:8;28930:25;:42::i;:::-;29017:26;;;;;;;:19;:26;;;;;:31;;29047:1;;29017:26;:31;;29047:1;;29017:31;:::i;:::-;;;;-1:-1:-1;;;;28631:425:0:o;28112:405::-;28275:1;28244:19;;;:9;:19;;;;;;:33;:19;:33;28237:41;;;;:::i;:::-;28318:19;;;;:9;:19;;;;;;;;:25;;;;;;;;;;;;;23417:27;;;:19;:27;;;;;;;;26673:20;:25;;;;;:40;;;;;;;;:51;;;26735:27;;;:17;:27;;;;;:43;;;;28480:24;;;;;;:29;;-1:-1:-1;;28318:19:0;28480:29;;-1:-1:-1;;28480:29:0;:::i;36979:330::-;37043:4;37111:17;;;37104:25;;;;:::i;:::-;37202:26;37214:3;37219:8;37202:11;:26::i;:::-;37244:35;;37270:8;;37244:35;;;;37261:1;;37244:35;;37261:1;;37244:35;-1:-1:-1;37297:4:0;36979:330;;;;:::o;65036:723::-;65092:13;65313:5;65322:1;65313:10;65309:53;;-1:-1:-1;;65340:10:0;;;;;;;;;;;;;;;;;;65036:723::o;65309:53::-;65387:5;65372:12;65428:78;65435:9;;65428:78;;65461:8;;;;:::i;:::-;;-1:-1:-1;65484:10:0;;-1:-1:-1;65492:2:0;65484:10;;:::i;:::-;;;65428:78;;;65516:19;65548:6;65538:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;65538:17:0;;65516:39;;65566:154;65573:10;;65566:154;;65600:11;65610:1;65600:11;;:::i;:::-;;-1:-1:-1;65669:10:0;65677:2;65669:5;:10;:::i;:::-;65656:24;;:2;:24;:::i;:::-;65643:39;;65626:6;65633;65626:14;;;;;;;;:::i;:::-;;;;:56;;;;;;;;;;-1:-1:-1;65697:11:0;65706:2;65697:11;;:::i;:::-;;;65566:154;;14158:1790;14256:11;;14216:13;;14242:11;14282:8;;;14278:23;;-1:-1:-1;;14292:9:0;;;;;;;;;-1:-1:-1;14292:9:0;;;14158:1790;-1:-1:-1;14158:1790:0:o;14278:23::-;14353:18;14391:1;14380:7;:3;14386:1;14380:7;:::i;:::-;14379:13;;;;:::i;:::-;14374:19;;:1;:19;:::i;:::-;14353:40;-1:-1:-1;14451:19:0;14483:15;14353:40;14496:2;14483:15;:::i;:::-;14473:26;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14473:26:0;;14451:48;;14512:18;14533:5;;;;;;;;;;;;;;;;;14512:26;;14602:1;14595:5;14591:13;14647:2;14639:6;14635:15;14698:1;14666:960;14721:3;14718:1;14715:10;14666:960;;;14776:1;14819:12;;;;;14813:19;14914:4;14902:2;14898:14;;;;;14880:40;;14874:47;15066:2;15062:14;;;15058:25;;15044:40;;15038:47;15256:1;15252:13;;;15248:24;;15234:39;;15228:46;15437:16;;;;15423:31;;15417:38;14950:1;14946:11;;;15087:4;15034:58;;;14982:129;15136:11;;15224:57;;;15172:128;;;;15325:11;;15413:49;;15361:120;15510:3;15506:13;15539:22;;15609:1;15594:17;;;;14769:9;14666:960;;;14670:44;15658:1;15653:3;15649:11;15679:1;15674:84;;;;15777:1;15772:82;;;;15642:212;;15674:84;15726:16;15707:17;;;15700:43;15674:84;;15772:82;15824:14;15805:17;;;15798:41;15642:212;-1:-1:-1;;;15870:26:0;;;15877:6;14158:1790;-1:-1:-1;;;;14158:1790:0:o;26966:1039::-;23417:27;;;27087:21;23417:27;;;:19;:27;;;;;;27111:19;;27129:1;;27111:19;:::i;:::-;27141:21;27165:27;;;:17;:27;;;;;;27087:43;;-1:-1:-1;27209:30:0;;;27205:793;;27300:27;;;27345:1;27300:27;;;:20;:27;;;;;;;;:42;;;;;;;;:46;;;27402:27;;;:17;:27;;;;;:31;27205:793;;;27488:27;;;;;27466:19;27488:27;;;:20;:27;;;;;;;;:42;;;;;;;;;;;27611;;;;;;:56;;;27723:30;;:17;:30;;;;;;:46;;;;27853;;;;27955:27;;;;;:31;26966:1039::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:177:1:-;99:66;92:5;88:78;81:5;78:89;68:117;;181:1;178;171:12;196:245;254:6;307:2;295:9;286:7;282:23;278:32;275:52;;;323:1;320;313:12;275:52;362:9;349:23;381:30;405:5;381:30;:::i;820:615::-;906:6;914;967:2;955:9;946:7;942:23;938:32;935:52;;;983:1;980;973:12;935:52;1023:9;1010:23;1052:18;1093:2;1085:6;1082:14;1079:34;;;1109:1;1106;1099:12;1079:34;1147:6;1136:9;1132:22;1122:32;;1192:7;1185:4;1181:2;1177:13;1173:27;1163:55;;1214:1;1211;1204:12;1163:55;1254:2;1241:16;1280:2;1272:6;1269:14;1266:34;;;1296:1;1293;1286:12;1266:34;1349:7;1344:2;1334:6;1331:1;1327:14;1323:2;1319:23;1315:32;1312:45;1309:65;;;1370:1;1367;1360:12;1309:65;1401:2;1393:11;;;;;1423:6;;-1:-1:-1;820:615:1;;-1:-1:-1;;;;820:615:1:o;1440:258::-;1512:1;1522:113;1536:6;1533:1;1530:13;1522:113;;;1612:11;;;1606:18;1593:11;;;1586:39;1558:2;1551:10;1522:113;;;1653:6;1650:1;1647:13;1644:48;;;-1:-1:-1;;1688:1:1;1670:16;;1663:27;1440:258::o;1703:317::-;1745:3;1783:5;1777:12;1810:6;1805:3;1798:19;1826:63;1882:6;1875:4;1870:3;1866:14;1859:4;1852:5;1848:16;1826:63;:::i;:::-;1934:2;1922:15;1939:66;1918:88;1909:98;;;;2009:4;1905:109;;1703:317;-1:-1:-1;;1703:317:1:o;2025:220::-;2174:2;2163:9;2156:21;2137:4;2194:45;2235:2;2224:9;2220:18;2212:6;2194:45;:::i;2250:180::-;2309:6;2362:2;2350:9;2341:7;2337:23;2333:32;2330:52;;;2378:1;2375;2368:12;2330:52;-1:-1:-1;2401:23:1;;2250:180;-1:-1:-1;2250:180:1:o;2666:154::-;2752:42;2745:5;2741:54;2734:5;2731:65;2721:93;;2810:1;2807;2800:12;2825:315;2893:6;2901;2954:2;2942:9;2933:7;2929:23;2925:32;2922:52;;;2970:1;2967;2960:12;2922:52;3009:9;2996:23;3028:31;3053:5;3028:31;:::i;:::-;3078:5;3130:2;3115:18;;;;3102:32;;-1:-1:-1;;;2825:315:1:o;3145:248::-;3213:6;3221;3274:2;3262:9;3253:7;3249:23;3245:32;3242:52;;;3290:1;3287;3280:12;3242:52;-1:-1:-1;;3313:23:1;;;3383:2;3368:18;;;3355:32;;-1:-1:-1;3145:248:1:o;3822:456::-;3899:6;3907;3915;3968:2;3956:9;3947:7;3943:23;3939:32;3936:52;;;3984:1;3981;3974:12;3936:52;4023:9;4010:23;4042:31;4067:5;4042:31;:::i;:::-;4092:5;-1:-1:-1;4149:2:1;4134:18;;4121:32;4162:33;4121:32;4162:33;:::i;:::-;3822:456;;4214:7;;-1:-1:-1;;;4268:2:1;4253:18;;;;4240:32;;3822:456::o;4472:247::-;4531:6;4584:2;4572:9;4563:7;4559:23;4555:32;4552:52;;;4600:1;4597;4590:12;4552:52;4639:9;4626:23;4658:31;4683:5;4658:31;:::i;4724:632::-;4895:2;4947:21;;;5017:13;;4920:18;;;5039:22;;;4866:4;;4895:2;5118:15;;;;5092:2;5077:18;;;4866:4;5161:169;5175:6;5172:1;5169:13;5161:169;;;5236:13;;5224:26;;5305:15;;;;5270:12;;;;5197:1;5190:9;5161:169;;;-1:-1:-1;5347:3:1;;4724:632;-1:-1:-1;;;;;;4724:632:1:o;5557:118::-;5643:5;5636:13;5629:21;5622:5;5619:32;5609:60;;5665:1;5662;5655:12;5680:382;5745:6;5753;5806:2;5794:9;5785:7;5781:23;5777:32;5774:52;;;5822:1;5819;5812:12;5774:52;5861:9;5848:23;5880:31;5905:5;5880:31;:::i;:::-;5930:5;-1:-1:-1;5987:2:1;5972:18;;5959:32;6000:30;5959:32;6000:30;:::i;:::-;6049:7;6039:17;;;5680:382;;;;;:::o;6334:184::-;6386:77;6383:1;6376:88;6483:4;6480:1;6473:15;6507:4;6504:1;6497:15;6523:1325;6618:6;6626;6634;6642;6695:3;6683:9;6674:7;6670:23;6666:33;6663:53;;;6712:1;6709;6702:12;6663:53;6751:9;6738:23;6770:31;6795:5;6770:31;:::i;:::-;6820:5;-1:-1:-1;6877:2:1;6862:18;;6849:32;6890:33;6849:32;6890:33;:::i;:::-;6942:7;-1:-1:-1;6996:2:1;6981:18;;6968:32;;-1:-1:-1;7051:2:1;7036:18;;7023:32;7074:18;7104:14;;;7101:34;;;7131:1;7128;7121:12;7101:34;7169:6;7158:9;7154:22;7144:32;;7214:7;7207:4;7203:2;7199:13;7195:27;7185:55;;7236:1;7233;7226:12;7185:55;7272:2;7259:16;7294:2;7290;7287:10;7284:36;;;7300:18;;:::i;:::-;7434:2;7428:9;7496:4;7488:13;;7339:66;7484:22;;;7508:2;7480:31;7476:40;7464:53;;;7532:18;;;7552:22;;;7529:46;7526:72;;;7578:18;;:::i;:::-;7618:10;7614:2;7607:22;7653:2;7645:6;7638:18;7693:7;7688:2;7683;7679;7675:11;7671:20;7668:33;7665:53;;;7714:1;7711;7704:12;7665:53;7770:2;7765;7761;7757:11;7752:2;7744:6;7740:15;7727:46;7815:1;7810:2;7805;7797:6;7793:15;7789:24;7782:35;7836:6;7826:16;;;;;;;6523:1325;;;;;;;:::o;7853:383::-;7930:6;7938;7946;7999:2;7987:9;7978:7;7974:23;7970:32;7967:52;;;8015:1;8012;8005:12;7967:52;8051:9;8038:23;8028:33;;8108:2;8097:9;8093:18;8080:32;8070:42;;8162:2;8151:9;8147:18;8134:32;8175:31;8200:5;8175:31;:::i;:::-;8225:5;8215:15;;;7853:383;;;;;:::o;8506:388::-;8574:6;8582;8635:2;8623:9;8614:7;8610:23;8606:32;8603:52;;;8651:1;8648;8641:12;8603:52;8690:9;8677:23;8709:31;8734:5;8709:31;:::i;:::-;8759:5;-1:-1:-1;8816:2:1;8801:18;;8788:32;8829:33;8788:32;8829:33;:::i;8899:184::-;8951:77;8948:1;8941:88;9048:4;9045:1;9038:15;9072:4;9069:1;9062:15;9088:184;9140:77;9137:1;9130:88;9237:4;9234:1;9227:15;9261:4;9258:1;9251:15;9277:195;9316:3;9347:66;9340:5;9337:77;9334:103;;9417:18;;:::i;:::-;-1:-1:-1;9464:1:1;9453:13;;9277:195::o;9813:184::-;9865:77;9862:1;9855:88;9962:4;9959:1;9952:15;9986:4;9983:1;9976:15;10002:128;10042:3;10073:1;10069:6;10066:1;10063:13;10060:39;;;10079:18;;:::i;:::-;-1:-1:-1;10115:9:1;;10002:128::o;10135:125::-;10175:4;10203:1;10200;10197:8;10194:34;;;10208:18;;:::i;:::-;-1:-1:-1;10245:9:1;;10135:125::o;10265:228::-;10305:7;10431:1;10363:66;10359:74;10356:1;10353:81;10348:1;10341:9;10334:17;10330:105;10327:131;;;10438:18;;:::i;:::-;-1:-1:-1;10478:9:1;;10265:228::o;10498:184::-;10550:77;10547:1;10540:88;10647:4;10644:1;10637:15;10671:4;10668:1;10661:15;10687:120;10727:1;10753;10743:35;;10758:18;;:::i;:::-;-1:-1:-1;10792:9:1;;10687:120::o;13309:512::-;13503:4;13532:42;13613:2;13605:6;13601:15;13590:9;13583:34;13665:2;13657:6;13653:15;13648:2;13637:9;13633:18;13626:43;;13705:6;13700:2;13689:9;13685:18;13678:34;13748:3;13743:2;13732:9;13728:18;13721:31;13769:46;13810:3;13799:9;13795:19;13787:6;13769:46;:::i;13826:249::-;13895:6;13948:2;13936:9;13927:7;13923:23;13919:32;13916:52;;;13964:1;13961;13954:12;13916:52;13996:9;13990:16;14015:30;14039:5;14015:30;:::i;15191:184::-;15261:6;15314:2;15302:9;15293:7;15289:23;15285:32;15282:52;;;15330:1;15327;15320:12;15282:52;-1:-1:-1;15353:16:1;;15191:184;-1:-1:-1;15191:184:1:o;15682:245::-;15749:6;15802:2;15790:9;15781:7;15777:23;15773:32;15770:52;;;15818:1;15815;15808:12;15770:52;15850:9;15844:16;15869:28;15891:5;15869:28;:::i;18029:725::-;18068:7;18116:1;18112:2;18101:17;18153:1;18149:2;18138:17;18174:34;18236:1;18231:3;18227:11;18266:1;18261:3;18257:11;18313:3;18309:2;18305:12;18300:3;18297:21;18292:2;18288;18284:11;18280:39;18277:65;;;18322:18;;:::i;:::-;18361:66;18455:1;18450:3;18446:11;18504:3;18500:2;18495:13;18490:3;18486:23;18481:2;18477;18473:11;18469:41;18466:67;;;18513:18;;:::i;:::-;18561:1;18556:3;18552:11;18542:21;;18610:3;18606:2;18601:13;18596:3;18592:23;18587:2;18583;18579:11;18575:41;18572:67;;;18619:18;;:::i;:::-;18686:3;18682:2;18677:13;18672:3;18668:23;18663:2;18659;18655:11;18651:41;18648:67;;;18695:18;;:::i;:::-;-1:-1:-1;;;18735:13:1;;;;;18029:725;-1:-1:-1;;;;;18029:725:1:o;18759:425::-;18798:4;18843:1;18839:2;18828:17;18880:1;18876:2;18865:17;18910:1;18905:3;18901:11;19021:3;18953:66;18949:76;18944:3;18940:86;18935:2;18928:10;18924:103;18921:129;;;19030:18;;:::i;:::-;19119:3;19083:34;19079:44;19074:3;19070:54;19066:2;19062:63;19059:89;;;19128:18;;:::i;:::-;-1:-1:-1;19165:13:1;;;18759:425;-1:-1:-1;;;18759:425:1:o;19189:423::-;19228:3;19272:1;19268:2;19257:17;19309:1;19305:2;19294:17;19339:1;19334:3;19330:11;19418:3;19382:34;19378:44;19373:3;19369:54;19364:2;19357:10;19353:71;19350:97;;;19427:18;;:::i;:::-;19548:3;19480:66;19476:76;19471:3;19467:86;19463:2;19459:95;19456:121;;;19557:18;;:::i;:::-;-1:-1:-1;19593:13:1;;19189:423;-1:-1:-1;;;19189:423:1:o;19966:184::-;20018:77;20015:1;20008:88;20115:4;20112:1;20105:15;20139:4;20136:1;20129:15;20558:614;20802:25;;;20858:2;20843:18;;20836:34;;;20789:3;20774:19;;20900:1;20889:13;;20879:201;;20936:77;20933:1;20926:88;21037:4;21034:1;21027:15;21065:4;21062:1;21055:15;20879:201;21111:2;21096:18;;21089:34;;;;21154:2;21139:18;21132:34;20558:614;;-1:-1:-1;;20558:614:1:o;21177:392::-;21216:1;21258;21254:2;21243:17;21295:1;21291:2;21280:17;21316:3;21306:37;;21323:18;;:::i;:::-;21444:66;21439:3;21436:75;21367:66;21362:3;21359:75;21355:157;21352:183;;;21515:18;;:::i;:::-;21549:14;;;21177:392;-1:-1:-1;;;21177:392:1:o;21574:369::-;21613:4;21649:1;21646;21642:9;21758:1;21690:66;21686:74;21683:1;21679:82;21674:2;21667:10;21663:99;21660:125;;;21765:18;;:::i;:::-;21884:1;21816:66;21812:74;21809:1;21805:82;21801:2;21797:91;21794:117;;;21891:18;;:::i;:::-;-1:-1:-1;;21928:9:1;;21574:369::o;21948:933::-;22329:3;22367:6;22361:13;22383:53;22429:6;22424:3;22417:4;22409:6;22405:17;22383:53;:::i;:::-;22497:8;22458:16;;;22483:23;;;22531:13;;22553:65;22531:13;22605:1;22594:13;;22587:4;22575:17;;22553:65;:::i;:::-;22685:66;22681:1;22637:20;;;;22673:10;;;22666:86;22781:66;22776:2;22768:11;;22761:87;22872:2;22864:11;;21948:933;-1:-1:-1;;;;21948:933:1:o;22886:939::-;23267:3;23305:6;23299:13;23321:53;23367:6;23362:3;23355:4;23347:6;23343:17;23321:53;:::i;:::-;23435:12;23396:16;;;23421:27;;;23473:13;;23495:66;23473:13;23547:2;23536:14;;23529:4;23517:17;;23495:66;:::i;:::-;23629;23624:2;23580:20;;;;23616:11;;;23609:87;23725:66;23720:2;23712:11;;23705:87;23816:2;23808:11;;22886:939;-1:-1:-1;;;;22886:939:1:o;23830:940::-;24211:3;24249:6;24243:13;24265:53;24311:6;24306:3;24299:4;24291:6;24287:17;24265:53;:::i;:::-;24379:13;24340:16;;;24365:28;;;24418:13;;24440:66;24418:13;24492:2;24481:14;;24474:4;24462:17;;24440:66;:::i;:::-;24574;24569:2;24525:20;;;;24561:11;;;24554:87;24670:66;24665:2;24657:11;;24650:87;24761:2;24753:11;;23830:940;-1:-1:-1;;;;23830:940:1:o;24775:786::-;25156:3;25194:6;25188:13;25210:53;25256:6;25251:3;25244:4;25236:6;25232:17;25210:53;:::i;:::-;25324:8;25285:16;;;25310:23;;;25358:13;;25380:65;25358:13;25432:1;25421:13;;25414:4;25402:17;;25380:65;:::i;:::-;25512:15;25508:1;25464:20;;;;25500:10;;;25493:35;25552:2;25544:11;;24775:786;-1:-1:-1;;;;24775:786:1:o;25566:1376::-;26078:66;26073:3;26066:79;26048:3;26174:6;26168:13;26190:62;26245:6;26240:2;26235:3;26231:12;26224:4;26216:6;26212:17;26190:62;:::i;:::-;26316:66;26311:2;26271:16;;;26303:11;;;26296:87;26412:34;26407:2;26399:11;;26392:55;26476:34;26471:2;26463:11;;26456:55;26541:66;26535:3;26527:12;;26520:88;26638:25;26632:3;26624:12;;26617:47;26689:13;;26711:64;26689:13;26760:3;26752:12;;26745:4;26733:17;;26711:64;:::i;:::-;26841:66;26835:3;26794:17;;;;26827:12;;;26820:88;26932:3;26924:12;;25566:1376;-1:-1:-1;;;;25566:1376:1:o;26947:448::-;27209:31;27204:3;27197:44;27179:3;27270:6;27264:13;27286:62;27341:6;27336:2;27331:3;27327:12;27320:4;27312:6;27308:17;27286:62;:::i;:::-;27368:16;;;;27386:2;27364:25;;26947:448;-1:-1:-1;;26947:448:1:o;27761:112::-;27793:1;27819;27809:35;;27824:18;;:::i;:::-;-1:-1:-1;27858:9:1;;27761:112::o

Swarm Source

ipfs://ce2d56e9b552f4223adf6e5046fec4fed9a2ebe35db4e3f404955e97d0b4014a
Loading