Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- ResearchCertificate
- Optimization enabled
- false
- Compiler version
- v0.6.2+commit.bacdbe57
- EVM Version
- default
- Verified at
- 2023-10-23T12:15:49.077214Z
Contract source code
pragma solidity ^0.6.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if account is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, isContract will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Replacement for Soliditys transfer: sends amount wei to
* recipient, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by transfer, making them unable to receive funds via
* transfer. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to recipient, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call.value(amount)("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
pragma solidity ^0.6.0;
/**
* @dev Wrappers over Soliditys arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* SafeMath restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so its recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Soliditys + operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Soliditys - operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Soliditys - operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Soliditys * operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Soliditys / operator. Note: this function uses a
* revert opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Soliditys / operator. Note: this function uses a
* revert opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Soliditys % operator. This function uses a revert
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Soliditys % operator. This function uses a revert
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
pragma solidity ^0.6.0;
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with using Counters for Counters.Counter;
* Since it is not possible to overflow a 256 bit integer with increments of one, increment can skip the {SafeMath}
* overflow check, thereby saving gas. This does assume however correct usage, in that the underlying _value is never
* directly accessed.
*/
library Counters {
using SafeMath for uint256;
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
counter._value += 1;
}
function decrement(Counter storage counter) internal {
counter._value = counter._value.sub(1);
}
}
pragma solidity ^0.6.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
abstract contract IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as this.onERC721Received.selector. This
* function MAY throw to revert and reject the transfer.
* Note: the ERC721 contract address is always the message sender.
* @param operator The address which called safeTransferFrom function
* @param from The address which previously owned the token
* @param tokenId The NFT identifier which is being transferred
* @param data Additional data with no specified format
* @return bytes4 bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))
*/
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public virtual returns (bytes4);
}
pragma solidity ^0.6.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* interfaceId. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
pragma solidity ^0.6.0;
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts may inherit from this and call {_registerInterface} to declare
* their support of an interface.
*/
contract ERC165 is IERC165 {
/*
* bytes4(keccak256(supportsInterface(bytes4))) == 0x01ffc9a7
*/
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
* @dev Mapping of interface ids to whether or not its supported.
*/
mapping(bytes4 => bool) private _supportedInterfaces;
constructor () internal {
_registerInterface(_INTERFACE_ID_ERC165);
}
/**
* @dev See {IERC165-supportsInterface}.
*
* Time complexity O(1), guaranteed to always use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view override returns (bool) {
return _supportedInterfaces[interfaceId];
}
/**
* @dev Registers the contract as an implementer of the interface defined by
* interfaceId. Support of the actual ERC165 interface is automatic and
* registering its interface id is not required.
*
* See {IERC165-supportsInterface}.
*
* Requirements:
*
* - interfaceId cannot be the ERC165 invalid interface (0xffffffff).
*/
function _registerInterface(bytes4 interfaceId) internal virtual {
require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
_supportedInterfaces[interfaceId] = true;
}
}
pragma solidity ^0.6.2;
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of NFTs in owners account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the NFT specified by tokenId.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Transfers a specific NFT (tokenId) from one account (from) to
* another (to).
*
* - from, to cannot be zero.
* - tokenId must be owned by from.
* - If the caller is not from, it must be have been allowed to move this
* NFT by either {approve} or {setApprovalForAll}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers a specific NFT (tokenId) from one account (from) to
* another (to).
*
* Requirements:
* - If the caller is not from, it must be approved to move this NFT by
* either {approve} or {setApprovalForAll}.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}
pragma solidity ^0.6.2;
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
function tokenHash(uint256 tokenId) external view returns (string memory);
}
pragma solidity ^0.6.2;
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
function tokenByIndex(uint256 index) external view returns (uint256);
}
pragma solidity ^0.6.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
contract Context {
constructor () internal { }
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
pragma solidity ^0.6.0;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* onlyOwner, which can be applied to your functions to restrict their use to
* the owner.
*/
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* onlyOwner functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (newOwner).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
pragma solidity ^0.6.0;
/**
* @title ERC721 Non-Fungible Token Standard basic implementation
* @dev see https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721 is Context, ERC165, IERC721 {
using SafeMath for uint256;
using Address for address;
using Counters for Counters.Counter;
bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
mapping (uint256 => address) private _tokenOwner;
mapping (uint256 => address) private _tokenApprovals;
mapping (address => Counters.Counter) private _ownedTokensCount;
mapping (address => mapping (address => bool)) private _operatorApprovals;
/*
* bytes4(keccak256(balanceOf(address))) == 0x70a08231
* bytes4(keccak256(ownerOf(uint256))) == 0x6352211e
* bytes4(keccak256(approve(address,uint256))) == 0x095ea7b3
* bytes4(keccak256(getApproved(uint256))) == 0x081812fc
* bytes4(keccak256(setApprovalForAll(address,bool))) == 0xa22cb465
* bytes4(keccak256(isApprovedForAll(address,address))) == 0xe985e9c5
* bytes4(keccak256(transferFrom(address,address,uint256))) == 0x23b872dd
* bytes4(keccak256(safeTransferFrom(address,address,uint256))) == 0x42842e0e
* bytes4(keccak256(safeTransferFrom(address,address,uint256,bytes))) == 0xb88d4fde
*
* => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
* 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
*/
bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
constructor () public {
_registerInterface(_INTERFACE_ID_ERC721);
}
/**
* @dev Gets the balance of the specified address.
* @param owner address to query the balance of
* @return uint256 representing the amount owned by the passed address
*/
function balanceOf(address owner) public view override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _ownedTokensCount[owner].current();
}
/**
* @dev Gets the owner of the specified token ID.
* @param tokenId uint256 ID of the token to query the owner of
* @return address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 tokenId) public view override returns (address) {
address owner = _tokenOwner[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
/**
* @dev Approves another address to transfer the given token ID
* The zero address indicates there is no approved address.
* There can only be one approved address per token at a given time.
* Can only be called by the token owner or an approved operator.
* @param to address to be approved for the given token ID
* @param tokenId uint256 ID of the token to be approved
*/
function approve(address to, uint256 tokenId) public virtual override {
address owner = ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
/**
* @dev Gets the approved address for a token ID, or zero if no address set
* Reverts if the token ID does not exist.
* @param tokenId uint256 ID of the token to query the approval of
* @return address currently approved for the given token ID
*/
function getApproved(uint256 tokenId) public view override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
/**
* @dev Sets or unsets the approval of a given operator
* An operator is allowed to transfer all tokens of the sender on their behalf.
* @param operator operator address to set the approval
* @param approved representing the status of the approval to be set
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
require(operator != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev Tells whether an operator is approved by a given owner.
* @param owner owner address which you want to query the approval of
* @param operator operator address which you want to query the approval of
* @return bool whether the given operator is approved by the given owner
*/
function isApprovedForAll(address owner, address operator) public view override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev Transfers the ownership of a given token ID to another address.
* Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
* Requires the msg.sender to be the owner, approved, or operator.
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transferFrom(from, to, tokenId);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
* which is called upon a safe transfer, and return the magic value
* bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); otherwise,
* the transfer is reverted.
* Requires the msg.sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
* which is called upon a safe transfer, and return the magic value
* bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); otherwise,
* the transfer is reverted.
* Requires the _msgSender() to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransferFrom(from, to, tokenId, _data);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement onERC721Received,
* which is called upon a safe transfer, and return the magic value
* bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); otherwise,
* the transfer is reverted.
* Requires the msg.sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
_transferFrom(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Returns whether the specified token exists.
* @param tokenId uint256 ID of the token to query the existence of
* @return bool whether the token exists
*/
function _exists(uint256 tokenId) internal view returns (bool) {
address owner = _tokenOwner[tokenId];
return owner != address(0);
}
/**
* @dev Returns whether the given spender can transfer a given token ID.
* @param spender address of the spender to query
* @param tokenId uint256 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) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
/**
* @dev Internal function to safely mint a new token.
* Reverts if the given token ID already exists.
* If the target address is a contract, it must implement onERC721Received,
* which is called upon a safe transfer, and return the magic value
* bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); otherwise,
* the transfer is reverted.
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted
*/
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
/**
* @dev Internal function to safely mint a new token.
* Reverts if the given token ID already exists.
* If the target address is a contract, it must implement onERC721Received,
* which is called upon a safe transfer, and return the magic value
* bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); otherwise,
* the transfer is reverted.
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted
* @param _data bytes data to send along with a safe transfer check
*/
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
_mint(to, tokenId);
require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Internal function to mint a new token.
* Reverts if the given token ID already exists.
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted
*/
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_tokenOwner[tokenId] = to;
_ownedTokensCount[to].increment();
emit Transfer(address(0), to, tokenId);
}
/**
* @dev Internal function to burn a specific token.
* Reverts if the token does not exist.
* @param tokenId uint256 ID of the token being burned
*/
function _burn(uint256 tokenId) internal virtual {
address owner = ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
_ownedTokensCount[owner].decrement();
_tokenOwner[tokenId] = address(0);
emit Transfer(owner, address(0), tokenId);
}
/**
* @dev Internal function to transfer ownership of a given token ID to another address.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function _transferFrom(address from, address to, uint256 tokenId) internal virtual {
require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
_ownedTokensCount[from].decrement();
_ownedTokensCount[to].increment();
_tokenOwner[tokenId] = to;
emit Transfer(from, to, tokenId);
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
private returns (bool)
{
if (!to.isContract()) {
return true;
}
(bool success, bytes memory returndata) = to.call(abi.encodeWithSelector(
IERC721Receiver(to).onERC721Received.selector,
_msgSender(),
from,
tokenId,
_data
));
if (!success) {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert("ERC721: transfer to non ERC721Receiver implementer");
}
} else {
bytes4 retval = abi.decode(returndata, (bytes4));
return (retval == _ERC721_RECEIVED);
}
}
function _approve(address to, uint256 tokenId) private {
_tokenApprovals[tokenId] = to;
emit Approval(ownerOf(tokenId), to, tokenId);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning.
*
* Calling conditions:
*
* - when from and to are both non-zero, froms tokenId will be
* transferred to to.
* - when from is zero, tokenId will be minted for to.
* - when to is zero, froms tokenId will be burned.
* - from and to are never both zero.
*
* To learn more about hooks, head to xref:ROOT:using-hooks.adoc[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
}
pragma solidity ^0.6.0;
contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
string private _name;
string private _symbol;
mapping(uint256 => string) private _tokenURIs;
mapping(uint256 => string) private _hashIDs;
string private _baseURI;
/*
* bytes4(keccak256(name())) == 0x06fdde03
* bytes4(keccak256(symbol())) == 0x95d89b41
* bytes4(keccak256(tokenURI(uint256))) == 0xc87b56dd
*
* => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
*/
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
/**
* @dev Constructor function
*/
constructor (string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
_registerInterface(_INTERFACE_ID_ERC721_METADATA);
}
/**
* @dev Gets the token name.
* @return string representing the token name
*/
function name() external view override returns (string memory) {
return _name;
}
/**
* @dev Gets the token symbol.
* @return string representing the token symbol
*/
function symbol() external view override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the URI for a given token ID. May return an empty string.
*
* If the tokens URI is non-empty and a base URI was set (via
* {_setBaseURI}), it will be added to the token IDs URI as a prefix.
*
* Reverts if the token ID does not exist.
*/
function tokenURI(uint256 tokenId) external view override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory _tokenURI = _tokenURIs[tokenId];
if (bytes(_tokenURI).length == 0) {
return "";
} else {
return string(abi.encodePacked(_baseURI, _tokenURI));
}
}
/**
* @dev Returns the Hash for a given token ID. May return an empty string.
*
*
* Reverts if the token ID does not exist.
*/
function tokenHash(uint256 tokenId) external view override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: Hash query for nonexistent token");
string memory _tokenHash = _hashIDs[tokenId];
if (bytes(_tokenHash).length == 0) {
return "";
} else {
return string(abi.encodePacked(_tokenHash));
}
}
/**
* @dev Internal function to set the token URI for a given token.
*
* Reverts if the token ID does not exist.
*
* TIP: if all token IDs share a prefix (e.g. if your URIs look like
* http://api.myproject.com/token/<id>), use {_setBaseURI} to store
* it and save gas.
*/
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
/**
* @dev Internal function to set the token hash for a given token.
*
* Reverts if the token ID does not exist.
*
*/
function _setTokenHash(uint256 tokenId, string memory _tokenHash) internal virtual {
require(_exists(tokenId), "ERC721Metadata: Hash set of nonexistent token");
_hashIDs[tokenId] = _tokenHash;
}
/**
* @dev Internal function to set the base URI for all token IDs. It is
* automatically added as a prefix to the value returned in {tokenURI}.
*/
function _setBaseURI(string memory baseURI) internal virtual {
_baseURI = baseURI;
}
/**
* @dev Returns the base URI set via {_setBaseURI}. This will be
* automatically added as a preffix in {tokenURI} to each tokens URI, when
* they are non-empty.
*/
function baseURI() external view returns (string memory) {
return _baseURI;
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (to == address(0)) {
if (bytes(_tokenURIs[tokenId]).length != 0) {
delete _tokenURIs[tokenId];
}
}
}
}
pragma solidity ^0.6.0;
/**
* @title ERC-721 Non-Fungible Token with optional enumeration extension logic
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable {
mapping(address => uint256[]) private _ownedTokens;
mapping(uint256 => uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 => uint256) private _allTokensIndex;
/*
* bytes4(keccak256(totalSupply())) == 0x18160ddd
* bytes4(keccak256(tokenOfOwnerByIndex(address,uint256))) == 0x2f745c59
* bytes4(keccak256(tokenByIndex(uint256))) == 0x4f6ccce7
*
* => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
*/
bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
/**
* @dev Constructor function.
*/
constructor () public {
_registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
}
/**
* @dev Gets the token ID at a given index of the tokens list of the requested owner.
* @param owner address owning the tokens list to be accessed
* @param index uint256 representing the index to be accessed of the requested tokens list
* @return uint256 token ID at the given index of the tokens list owned by the requested address
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) {
require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
/**
* @dev Gets the total amount of tokens stored by the contract.
* @return uint256 representing the total amount of tokens
*/
function totalSupply() public view override returns (uint256) {
return _allTokens.length;
}
/**
* @dev Gets the token ID at a given index of all the tokens in this contract
* Reverts if the index is greater or equal to the total number of tokens.
* @param index uint256 representing the index to be accessed of the tokens list
* @return uint256 token ID at the given index of the tokens list
*/
function tokenByIndex(uint256 index) public view override returns (uint256) {
require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (from == address(0)) {
_addTokenToOwnerEnumeration(to, tokenId);
_addTokenToAllTokensEnumeration(tokenId);
} else if (to == address(0)) {
_removeTokenFromOwnerEnumeration(from, tokenId);
_ownedTokensIndex[tokenId] = 0;
_removeTokenFromAllTokensEnumeration(tokenId);
} else {
_removeTokenFromOwnerEnumeration(from, tokenId);
_addTokenToOwnerEnumeration(to, tokenId);
}
}
/**
* @dev Gets the list of token IDs of the requested owner.
* @param owner address owning the tokens
* @return uint256[] List of token IDs owned by the requested address
*/
function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
return _ownedTokens[owner];
}
/**
* @dev Private function to add a token to this extensions ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
_ownedTokensIndex[tokenId] = _ownedTokens[to].length;
_ownedTokens[to].push(tokenId);
}
/**
* @dev Private function to add a token to this extensions token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extensions ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the _ownedTokensIndex mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
uint256 tokenIndex = _ownedTokensIndex[tokenId];
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId;
_ownedTokensIndex[lastTokenId] = tokenIndex;
}
_ownedTokens[from].pop();
}
/**
* @dev Private function to remove a token from this extensions token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
uint256 lastTokenIndex = _allTokens.length.sub(1);
uint256 tokenIndex = _allTokensIndex[tokenId];
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId;
_allTokensIndex[lastTokenId] = tokenIndex;
_allTokens.pop();
_allTokensIndex[tokenId] = 0;
}
}
pragma solidity ^0.6.0;
/**
* @title Full ERC721 Token
* @dev This implementation includes all the required and some optional functionality of the ERC721 standard
* Moreover, it includes approve all functionality using operator terminology.
*
* See https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721Full is ERC721Enumerable, ERC721Metadata {
constructor (string memory name, string memory symbol) public ERC721Metadata(name, symbol) { }
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
virtual
override(ERC721Enumerable, ERC721Metadata)
internal
{
super._beforeTokenTransfer(from, to, tokenId);
}
}
pragma solidity ^0.6.0;
contract ResearchCertificate is ERC721Full, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721Full("ResearchObjectCertification", "ROC") public {
}
function createCertificate(address recipient, string memory tokenURI, string memory tokenHash) onlyOwner public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);
_setTokenHash(newItemId, tokenHash);
return newItemId;
}
function updateTokenURI(uint256 tokenID, string memory tokenURI) onlyOwner public returns (string memory) {
_setTokenURI(tokenID, tokenURI);
return tokenURI;
}
}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"approved","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"ApprovalForAll","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"operator","internalType":"address","indexed":true},{"type":"bool","name":"approved","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"approve","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"baseURI","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"createCertificate","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"string","name":"tokenURI","internalType":"string"},{"type":"string","name":"tokenHash","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getApproved","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isApprovedForAll","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"operator","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"ownerOf","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setApprovalForAll","inputs":[{"type":"address","name":"operator","internalType":"address"},{"type":"bool","name":"approved","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenByIndex","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"tokenHash","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenOfOwnerByIndex","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"tokenURI","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"updateTokenURI","inputs":[{"type":"uint256","name":"tokenID","internalType":"uint256"},{"type":"string","name":"tokenURI","internalType":"string"}]}]
Contract Creation Code
0x60806040523480156200001157600080fd5b506040518060400160405280601b81526020017f52657365617263684f626a65637443657274696669636174696f6e00000000008152506040518060400160405280600381526020017f524f4300000000000000000000000000000000000000000000000000000000008152508181620000986301ffc9a760e01b620001cd60201b60201c565b620000b06380ac58cd60e01b620001cd60201b60201c565b620000c863780e9d6360e01b620001cd60201b60201c565b8160099080519060200190620000e0929190620002de565b5080600a9080519060200190620000f9929190620002de565b5062000112635b5e139f60e01b620001cd60201b60201c565b50505050600062000128620002d660201b60201c565b905080600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3506200038d565b63ffffffff60e01b817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156200026a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4552433136353a20696e76616c696420696e746572666163652069640000000081525060200191505060405180910390fd5b6001600080837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b600033905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200032157805160ff191683800117855562000352565b8280016001018555821562000352579182015b828111156200035157825182559160200191906001019062000334565b5b50905062000361919062000365565b5090565b6200038a91905b80821115620003865760008160009055506001016200036c565b5090565b90565b6136a5806200039d6000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80636c0360eb116100c3578063a38643971161007c578063a386439714610842578063b88d4fde146108e9578063c87b56dd146109ee578063e985e9c514610a95578063f0e3611514610b11578063f2fde38b14610c975761014d565b80636c0360eb1461064057806370a08231146106c3578063715018a61461071b5780638da5cb5b1461072557806395d89b411461076f578063a22cb465146107f25761014d565b806318e97fd11161011557806318e97fd11461031457806323b872dd146104525780632f745c59146104c057806342842e0e146105225780634f6ccce7146105905780636352211e146105d25761014d565b806301ffc9a71461015257806306fdde03146101b7578063081812fc1461023a578063095ea7b3146102a857806318160ddd146102f6575b600080fd5b61019d6004803603602081101561016857600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169060200190929190505050610cdb565b604051808215151515815260200191505060405180910390f35b6101bf610d42565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ff5780820151818401526020810190506101e4565b50505050905090810190601f16801561022c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102666004803603602081101561025057600080fd5b8101908080359060200190929190505050610de4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102f4600480360360408110156102be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e7f565b005b6102fe610fc3565b6040518082815260200191505060405180910390f35b6103d76004803603604081101561032a57600080fd5b81019080803590602001909291908035906020019064010000000081111561035157600080fd5b82018360208201111561036357600080fd5b8035906020019184600183028401116401000000008311171561038557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610fd0565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156104175780820151818401526020810190506103fc565b50505050905090810190601f1680156104445780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104be6004803603606081101561046857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506110af565b005b61050c600480360360408110156104d657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611125565b6040518082815260200191505060405180910390f35b61058e6004803603606081101561053857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506111e4565b005b6105bc600480360360208110156105a657600080fd5b8101908080359060200190929190505050611204565b6040518082815260200191505060405180910390f35b6105fe600480360360208110156105e857600080fd5b8101908080359060200190929190505050611284565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61064861134c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561068857808201518184015260208101905061066d565b50505050905090810190601f1680156106b55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610705600480360360208110156106d957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506113ee565b6040518082815260200191505060405180910390f35b6107236114c3565b005b61072d61164e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610777611678565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156107b757808201518184015260208101905061079c565b50505050905090810190601f1680156107e45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6108406004803603604081101561080857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080351515906020019092919050505061171a565b005b61086e6004803603602081101561085857600080fd5b81019080803590602001909291905050506118d2565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6109ec600480360360808110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561096657600080fd5b82018360208201111561097857600080fd5b8035906020019184600183028401116401000000008311171561099a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611a78565b005b610a1a60048036036020811015610a0457600080fd5b8101908080359060200190929190505050611af0565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610a5a578082015181840152602081019050610a3f565b50505050905090810190601f168015610a875780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610af760048036036040811015610aab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611cf2565b604051808215151515815260200191505060405180910390f35b610c8160048036036060811015610b2757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610b6457600080fd5b820183602082011115610b7657600080fd5b80359060200191846001830284011164010000000083111715610b9857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610bfb57600080fd5b820183602082011115610c0d57600080fd5b80359060200191846001830284011164010000000083111715610c2f57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611d86565b6040518082815260200191505060405180910390f35b610cd960048036036020811015610cad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e93565b005b6000806000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff169050919050565b606060098054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610dda5780601f10610daf57610100808354040283529160200191610dda565b820191906000526020600020905b815481529060010190602001808311610dbd57829003601f168201915b5050505050905090565b6000610def826120a3565b610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180613542602c913960400191505060405180910390fd5b6002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000610e8a82611284565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610f11576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806135f26021913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610f30612115565b73ffffffffffffffffffffffffffffffffffffffff161480610f5f5750610f5e81610f59612115565b611cf2565b5b610fb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260388152602001806134b76038913960400191505060405180910390fd5b610fbe838361211d565b505050565b6000600780549050905090565b6060610fda612115565b73ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461109c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6110a683836121d6565b81905092915050565b6110c06110ba612115565b82612260565b611115576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260318152602001806136136031913960400191505060405180910390fd5b611120838383612354565b505050565b6000611130836113ee565b8210611187576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180613387602b913960400191505060405180910390fd5b600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481106111d157fe5b9060005260206000200154905092915050565b6111ff83838360405180602001604052806000815250611a78565b505050565b600061120e610fc3565b8210611265576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180613644602c913960400191505060405180910390fd5b6007828154811061127257fe5b90600052602060002001549050919050565b6000806001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611343576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806135196029913960400191505060405180910390fd5b80915050919050565b6060600d8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156113e45780601f106113b9576101008083540402835291602001916113e4565b820191906000526020600020905b8154815290600101906020018083116113c757829003601f168201915b5050505050905090565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611475576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a8152602001806134ef602a913960400191505060405180910390fd5b6114bc600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206125bc565b9050919050565b6114cb612115565b73ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461158d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6060600a8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156117105780601f106116e557610100808354040283529160200191611710565b820191906000526020600020905b8154815290600101906020018083116116f357829003601f168201915b5050505050905090565b611722612115565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156117c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4552433732313a20617070726f766520746f2063616c6c65720000000000000081525060200191505060405180910390fd5b80600460006117d0612115565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff1661187d612115565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051808215151515815260200191505060405180910390a35050565b60606118dd826120a3565b611932576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806134376030913960400191505060405180910390fd5b6060600c60008481526020019081526020016000208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156119db5780601f106119b0576101008083540402835291602001916119db565b820191906000526020600020905b8154815290600101906020018083116119be57829003601f168201915b50505050509050600081511415611a045760405180602001604052806000815250915050611a73565b806040516020018082805190602001908083835b60208310611a3b5780518252602082019150602081019050602083039250611a18565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040529150505b919050565b611a89611a83612115565b83612260565b611ade576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260318152602001806136136031913960400191505060405180910390fd5b611aea848484846125ca565b50505050565b6060611afb826120a3565b611b50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f8152602001806135c3602f913960400191505060405180910390fd5b6060600b60008481526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611bf95780601f10611bce57610100808354040283529160200191611bf9565b820191906000526020600020905b815481529060010190602001808311611bdc57829003601f168201915b50505050509050600081511415611c225760405180602001604052806000815250915050611ced565b600d816040516020018083805460018160011615610100020316600290048015611c835780601f10611c61576101008083540402835291820191611c83565b820191906000526020600020905b815481529060010190602001808311611c6f575b505082805190602001908083835b60208310611cb45780518252602082019150602081019050602083039250611c91565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529150505b919050565b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000611d90612115565b73ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611e52576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b611e5c600f61263c565b6000611e68600f6125bc565b9050611e748582612652565b611e7e81856121d6565b611e888184612876565b809150509392505050565b611e9b612115565b73ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f5d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611fe3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806133e46026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a380600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415915050919050565b600033905090565b816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff1661219083611284565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6121df826120a3565b612234576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c81526020018061356e602c913960400191505060405180910390fd5b80600b6000848152602001908152602001600020908051906020019061225b929190613299565b505050565b600061226b826120a3565b6122c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c81526020018061348b602c913960400191505060405180910390fd5b60006122cb83611284565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061233a57508373ffffffffffffffffffffffffffffffffffffffff1661232284610de4565b73ffffffffffffffffffffffffffffffffffffffff16145b8061234b575061234a8185611cf2565b5b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1661237482611284565b73ffffffffffffffffffffffffffffffffffffffff16146123e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061359a6029913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612466576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806134676024913960400191505060405180910390fd5b612471838383612900565b61247c60008261211d565b6124c3600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612910565b61250a600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061263c565b816001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b600081600001549050919050565b6125d5848484612354565b6125e184848484612933565b612636576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806133b26032913960400191505060405180910390fd5b50505050565b6001816000016000828254019250508190555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156126f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4552433732313a206d696e7420746f20746865207a65726f206164647265737381525060200191505060405180910390fd5b6126fe816120a3565b15612771576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000081525060200191505060405180910390fd5b61277d60008383612900565b816001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550612816600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061263c565b808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050565b61287f826120a3565b6128d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d81526020018061340a602d913960400191505060405180910390fd5b80600c600084815260200190815260200160002090805190602001906128fb929190613299565b505050565b61290b838383612c56565b505050565b61292860018260000154612ceb90919063ffffffff16565b816000018190555050565b60006129548473ffffffffffffffffffffffffffffffffffffffff16612d35565b6129615760019050612c4e565b600060608573ffffffffffffffffffffffffffffffffffffffff1663150b7a0260e01b61298c612115565b898888604051602401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612a3c578082015181840152602081019050612a21565b50505050905090810190601f168015612a695780820380516001836020036101000a031916815260200191505b5095505050505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310612b015780518252602082019150602081019050602083039250612ade565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612b63576040519150601f19603f3d011682016040523d82523d6000602084013e612b68565b606091505b509150915081612bd657600081511115612b855780518082602001fd5b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806133b26032913960400191505060405180910390fd5b6000818060200190516020811015612bed57600080fd5b8101908080519060200190929190505050905063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161493505050505b949350505050565b612c61838383612d80565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612ce6576000600b600083815260200190815260200160002080546001816001161561010002031660029004905014612ce557600b60008281526020019081526020016000206000612ce49190613319565b5b5b505050565b6000612d2d83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612e59565b905092915050565b60008060007fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060001b9050833f9150808214158015612d7757506000801b8214155b92505050919050565b612d8b838383612f19565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612dd857612dca8282612f1e565b612dd381612fe2565b612e54565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612e3e57612e17838261302b565b60006006600083815260200190815260200160002081905550612e39816131d4565b612e53565b612e48838261302b565b612e528282612f1e565b5b5b505050565b6000838311158290612f06576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612ecb578082015181840152602081019050612eb0565b50505050905090810190601f168015612ef85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b505050565b600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506006600083815260200190815260200160002081905550600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002001600090919091909150555050565b6007805490506008600083815260200190815260200160002081905550600781908060018154018082558091505060019003906000526020600020016000909190919091505550565b60006130836001600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612ceb90919063ffffffff16565b9050600060066000848152602001908152602001600020549050818114613170576000600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002083815481106130f057fe5b9060005260206000200154905080600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020838154811061314857fe5b9060005260206000200181905550816006600083815260200190815260200160002081905550505b600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054806131b857fe5b6001900381819060005260206000200160009055905550505050565b60006131ef6001600780549050612ceb90919063ffffffff16565b905060006008600084815260200190815260200160002054905060006007838154811061321857fe5b90600052602060002001549050806007838154811061323357fe5b9060005260206000200181905550816008600083815260200190815260200160002081905550600780548061326457fe5b600190038181906000526020600020016000905590556000600860008681526020019081526020016000208190555050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106132da57805160ff1916838001178555613308565b82800160010185558215613308579182015b828111156133075782518255916020019190600101906132ec565b5b5090506133159190613361565b5090565b50805460018160011615610100020316600290046000825580601f1061333f575061335e565b601f01602090049060005260206000209081019061335d9190613361565b5b50565b61338391905b8082111561337f576000816000905550600101613367565b5090565b9056fe455243373231456e756d657261626c653a206f776e657220696e646578206f7574206f6620626f756e64734552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734552433732314d657461646174613a204861736820736574206f66206e6f6e6578697374656e7420746f6b656e4552433732314d657461646174613a204861736820717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a207472616e7366657220746f20746865207a65726f20616464726573734552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c4552433732313a2062616c616e636520717565727920666f7220746865207a65726f20616464726573734552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732314d657461646174613a2055524920736574206f66206e6f6e6578697374656e7420746f6b656e4552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732314d657461646174613a2055524920717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76616c20746f2063757272656e74206f776e65724552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564455243373231456e756d657261626c653a20676c6f62616c20696e646578206f7574206f6620626f756e6473a2646970667358221220c11f6e699e59272e8dede945c7d1e7e8b6af78ff8a32dcbf90bd53dac2cf946264736f6c63430006020033
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c80636c0360eb116100c3578063a38643971161007c578063a386439714610842578063b88d4fde146108e9578063c87b56dd146109ee578063e985e9c514610a95578063f0e3611514610b11578063f2fde38b14610c975761014d565b80636c0360eb1461064057806370a08231146106c3578063715018a61461071b5780638da5cb5b1461072557806395d89b411461076f578063a22cb465146107f25761014d565b806318e97fd11161011557806318e97fd11461031457806323b872dd146104525780632f745c59146104c057806342842e0e146105225780634f6ccce7146105905780636352211e146105d25761014d565b806301ffc9a71461015257806306fdde03146101b7578063081812fc1461023a578063095ea7b3146102a857806318160ddd146102f6575b600080fd5b61019d6004803603602081101561016857600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169060200190929190505050610cdb565b604051808215151515815260200191505060405180910390f35b6101bf610d42565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ff5780820151818401526020810190506101e4565b50505050905090810190601f16801561022c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102666004803603602081101561025057600080fd5b8101908080359060200190929190505050610de4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102f4600480360360408110156102be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e7f565b005b6102fe610fc3565b6040518082815260200191505060405180910390f35b6103d76004803603604081101561032a57600080fd5b81019080803590602001909291908035906020019064010000000081111561035157600080fd5b82018360208201111561036357600080fd5b8035906020019184600183028401116401000000008311171561038557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610fd0565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156104175780820151818401526020810190506103fc565b50505050905090810190601f1680156104445780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104be6004803603606081101561046857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506110af565b005b61050c600480360360408110156104d657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611125565b6040518082815260200191505060405180910390f35b61058e6004803603606081101561053857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506111e4565b005b6105bc600480360360208110156105a657600080fd5b8101908080359060200190929190505050611204565b6040518082815260200191505060405180910390f35b6105fe600480360360208110156105e857600080fd5b8101908080359060200190929190505050611284565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61064861134c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561068857808201518184015260208101905061066d565b50505050905090810190601f1680156106b55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610705600480360360208110156106d957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506113ee565b6040518082815260200191505060405180910390f35b6107236114c3565b005b61072d61164e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610777611678565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156107b757808201518184015260208101905061079c565b50505050905090810190601f1680156107e45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6108406004803603604081101561080857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080351515906020019092919050505061171a565b005b61086e6004803603602081101561085857600080fd5b81019080803590602001909291905050506118d2565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6109ec600480360360808110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561096657600080fd5b82018360208201111561097857600080fd5b8035906020019184600183028401116401000000008311171561099a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611a78565b005b610a1a60048036036020811015610a0457600080fd5b8101908080359060200190929190505050611af0565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610a5a578082015181840152602081019050610a3f565b50505050905090810190601f168015610a875780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610af760048036036040811015610aab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611cf2565b604051808215151515815260200191505060405180910390f35b610c8160048036036060811015610b2757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610b6457600080fd5b820183602082011115610b7657600080fd5b80359060200191846001830284011164010000000083111715610b9857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610bfb57600080fd5b820183602082011115610c0d57600080fd5b80359060200191846001830284011164010000000083111715610c2f57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611d86565b6040518082815260200191505060405180910390f35b610cd960048036036020811015610cad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e93565b005b6000806000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff169050919050565b606060098054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610dda5780601f10610daf57610100808354040283529160200191610dda565b820191906000526020600020905b815481529060010190602001808311610dbd57829003601f168201915b5050505050905090565b6000610def826120a3565b610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180613542602c913960400191505060405180910390fd5b6002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000610e8a82611284565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610f11576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806135f26021913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610f30612115565b73ffffffffffffffffffffffffffffffffffffffff161480610f5f5750610f5e81610f59612115565b611cf2565b5b610fb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260388152602001806134b76038913960400191505060405180910390fd5b610fbe838361211d565b505050565b6000600780549050905090565b6060610fda612115565b73ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461109c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6110a683836121d6565b81905092915050565b6110c06110ba612115565b82612260565b611115576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260318152602001806136136031913960400191505060405180910390fd5b611120838383612354565b505050565b6000611130836113ee565b8210611187576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180613387602b913960400191505060405180910390fd5b600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481106111d157fe5b9060005260206000200154905092915050565b6111ff83838360405180602001604052806000815250611a78565b505050565b600061120e610fc3565b8210611265576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c815260200180613644602c913960400191505060405180910390fd5b6007828154811061127257fe5b90600052602060002001549050919050565b6000806001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611343576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806135196029913960400191505060405180910390fd5b80915050919050565b6060600d8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156113e45780601f106113b9576101008083540402835291602001916113e4565b820191906000526020600020905b8154815290600101906020018083116113c757829003601f168201915b5050505050905090565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611475576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a8152602001806134ef602a913960400191505060405180910390fd5b6114bc600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206125bc565b9050919050565b6114cb612115565b73ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461158d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6060600a8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156117105780601f106116e557610100808354040283529160200191611710565b820191906000526020600020905b8154815290600101906020018083116116f357829003601f168201915b5050505050905090565b611722612115565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156117c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4552433732313a20617070726f766520746f2063616c6c65720000000000000081525060200191505060405180910390fd5b80600460006117d0612115565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff1661187d612115565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051808215151515815260200191505060405180910390a35050565b60606118dd826120a3565b611932576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806134376030913960400191505060405180910390fd5b6060600c60008481526020019081526020016000208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156119db5780601f106119b0576101008083540402835291602001916119db565b820191906000526020600020905b8154815290600101906020018083116119be57829003601f168201915b50505050509050600081511415611a045760405180602001604052806000815250915050611a73565b806040516020018082805190602001908083835b60208310611a3b5780518252602082019150602081019050602083039250611a18565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040529150505b919050565b611a89611a83612115565b83612260565b611ade576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260318152602001806136136031913960400191505060405180910390fd5b611aea848484846125ca565b50505050565b6060611afb826120a3565b611b50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f8152602001806135c3602f913960400191505060405180910390fd5b6060600b60008481526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611bf95780601f10611bce57610100808354040283529160200191611bf9565b820191906000526020600020905b815481529060010190602001808311611bdc57829003601f168201915b50505050509050600081511415611c225760405180602001604052806000815250915050611ced565b600d816040516020018083805460018160011615610100020316600290048015611c835780601f10611c61576101008083540402835291820191611c83565b820191906000526020600020905b815481529060010190602001808311611c6f575b505082805190602001908083835b60208310611cb45780518252602082019150602081019050602083039250611c91565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529150505b919050565b6000600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000611d90612115565b73ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611e52576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b611e5c600f61263c565b6000611e68600f6125bc565b9050611e748582612652565b611e7e81856121d6565b611e888184612876565b809150509392505050565b611e9b612115565b73ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f5d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611fe3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806133e46026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600e60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a380600e60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415915050919050565b600033905090565b816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff1661219083611284565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6121df826120a3565b612234576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c81526020018061356e602c913960400191505060405180910390fd5b80600b6000848152602001908152602001600020908051906020019061225b929190613299565b505050565b600061226b826120a3565b6122c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c81526020018061348b602c913960400191505060405180910390fd5b60006122cb83611284565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061233a57508373ffffffffffffffffffffffffffffffffffffffff1661232284610de4565b73ffffffffffffffffffffffffffffffffffffffff16145b8061234b575061234a8185611cf2565b5b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1661237482611284565b73ffffffffffffffffffffffffffffffffffffffff16146123e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061359a6029913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612466576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806134676024913960400191505060405180910390fd5b612471838383612900565b61247c60008261211d565b6124c3600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612910565b61250a600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061263c565b816001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b600081600001549050919050565b6125d5848484612354565b6125e184848484612933565b612636576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806133b26032913960400191505060405180910390fd5b50505050565b6001816000016000828254019250508190555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156126f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4552433732313a206d696e7420746f20746865207a65726f206164647265737381525060200191505060405180910390fd5b6126fe816120a3565b15612771576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000081525060200191505060405180910390fd5b61277d60008383612900565b816001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550612816600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061263c565b808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050565b61287f826120a3565b6128d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d81526020018061340a602d913960400191505060405180910390fd5b80600c600084815260200190815260200160002090805190602001906128fb929190613299565b505050565b61290b838383612c56565b505050565b61292860018260000154612ceb90919063ffffffff16565b816000018190555050565b60006129548473ffffffffffffffffffffffffffffffffffffffff16612d35565b6129615760019050612c4e565b600060608573ffffffffffffffffffffffffffffffffffffffff1663150b7a0260e01b61298c612115565b898888604051602401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612a3c578082015181840152602081019050612a21565b50505050905090810190601f168015612a695780820380516001836020036101000a031916815260200191505b5095505050505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310612b015780518252602082019150602081019050602083039250612ade565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612b63576040519150601f19603f3d011682016040523d82523d6000602084013e612b68565b606091505b509150915081612bd657600081511115612b855780518082602001fd5b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806133b26032913960400191505060405180910390fd5b6000818060200190516020811015612bed57600080fd5b8101908080519060200190929190505050905063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161493505050505b949350505050565b612c61838383612d80565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612ce6576000600b600083815260200190815260200160002080546001816001161561010002031660029004905014612ce557600b60008281526020019081526020016000206000612ce49190613319565b5b5b505050565b6000612d2d83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612e59565b905092915050565b60008060007fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060001b9050833f9150808214158015612d7757506000801b8214155b92505050919050565b612d8b838383612f19565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612dd857612dca8282612f1e565b612dd381612fe2565b612e54565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612e3e57612e17838261302b565b60006006600083815260200190815260200160002081905550612e39816131d4565b612e53565b612e48838261302b565b612e528282612f1e565b5b5b505050565b6000838311158290612f06576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612ecb578082015181840152602081019050612eb0565b50505050905090810190601f168015612ef85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b505050565b600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506006600083815260200190815260200160002081905550600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002001600090919091909150555050565b6007805490506008600083815260200190815260200160002081905550600781908060018154018082558091505060019003906000526020600020016000909190919091505550565b60006130836001600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612ceb90919063ffffffff16565b9050600060066000848152602001908152602001600020549050818114613170576000600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002083815481106130f057fe5b9060005260206000200154905080600560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020838154811061314857fe5b9060005260206000200181905550816006600083815260200190815260200160002081905550505b600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054806131b857fe5b6001900381819060005260206000200160009055905550505050565b60006131ef6001600780549050612ceb90919063ffffffff16565b905060006008600084815260200190815260200160002054905060006007838154811061321857fe5b90600052602060002001549050806007838154811061323357fe5b9060005260206000200181905550816008600083815260200190815260200160002081905550600780548061326457fe5b600190038181906000526020600020016000905590556000600860008681526020019081526020016000208190555050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106132da57805160ff1916838001178555613308565b82800160010185558215613308579182015b828111156133075782518255916020019190600101906132ec565b5b5090506133159190613361565b5090565b50805460018160011615610100020316600290046000825580601f1061333f575061335e565b601f01602090049060005260206000209081019061335d9190613361565b5b50565b61338391905b8082111561337f576000816000905550600101613367565b5090565b9056fe455243373231456e756d657261626c653a206f776e657220696e646578206f7574206f6620626f756e64734552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734552433732314d657461646174613a204861736820736574206f66206e6f6e6578697374656e7420746f6b656e4552433732314d657461646174613a204861736820717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a207472616e7366657220746f20746865207a65726f20616464726573734552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c4552433732313a2062616c616e636520717565727920666f7220746865207a65726f20616464726573734552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732314d657461646174613a2055524920736574206f66206e6f6e6578697374656e7420746f6b656e4552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732314d657461646174613a2055524920717565727920666f72206e6f6e6578697374656e7420746f6b656e4552433732313a20617070726f76616c20746f2063757272656e74206f776e65724552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564455243373231456e756d657261626c653a20676c6f62616c20696e646578206f7574206f6620626f756e6473a2646970667358221220c11f6e699e59272e8dede945c7d1e7e8b6af78ff8a32dcbf90bd53dac2cf946264736f6c63430006020033