Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- ArtefinNFT
- Optimization enabled
- true
- Compiler version
- v0.8.17+commit.8df45f5f
- Optimization runs
- 1000
- EVM Version
- default
- Verified at
- 2024-09-26T15:24:34.446392Z
Contract source code
// SPDX-License-Identifier: GPL pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } } abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } } abstract contract Ownable is Context { address internal _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } abstract contract MinterRole is Ownable { mapping (address => bool) public minter_role; function setMinterRole(address _who, bool _status) public onlyOwner { minter_role[_who] = _status; } modifier onlyMinter { require(minter_role[msg.sender], "Minter role required"); _; } } //https://github.com/willitscale/solidity-util/blob/000a42d4d7c1491cde4381c29d4b775fa7e99aac/lib/Strings.sol#L317-L336 /** * Strings Library * * In summary this is a simple library of string functions which make simple * string operations less tedious in solidity. * * Please be aware these functions can be quite gas heavy so use them only when * necessary not to clog the blockchain with expensive transactions. * * @author James Lockhart <[email protected]> */ library Strings { /** * Concat (High gas cost) * * Appends two strings together and returns a new value * * @param _base When being used for a data type this is the extended object * otherwise this is the string which will be the concatenated * prefix * @param _value The value to be the concatenated suffix * @return string The resulting string from combinging the base and value */ function concat(string memory _base, string memory _value) internal pure returns (string memory) { bytes memory _baseBytes = bytes(_base); bytes memory _valueBytes = bytes(_value); assert(_valueBytes.length > 0); string memory _tmpValue = new string(_baseBytes.length + _valueBytes.length); bytes memory _newValue = bytes(_tmpValue); uint i; uint j; for (i = 0; i < _baseBytes.length; i++) { _newValue[j++] = _baseBytes[i]; } for (i = 0; i < _valueBytes.length; i++) { _newValue[j++] = _valueBytes[i]; } return string(_newValue); } /** * Index Of * * Locates and returns the position of a character within a string * * @param _base When being used for a data type this is the extended object * otherwise this is the string acting as the haystack to be * searched * @param _value The needle to search for, at present this is currently * limited to one character * @return int The position of the needle starting from 0 and returning -1 * in the case of no matches found */ function indexOf(string memory _base, string memory _value) internal pure returns (int) { return _indexOf(_base, _value, 0); } /** * Index Of * * Locates and returns the position of a character within a string starting * from a defined offset * * @param _base When being used for a data type this is the extended object * otherwise this is the string acting as the haystack to be * searched * @param _value The needle to search for, at present this is currently * limited to one character * @param _offset The starting point to start searching from which can start * from 0, but must not exceed the length of the string * @return int The position of the needle starting from 0 and returning -1 * in the case of no matches found */ function _indexOf(string memory _base, string memory _value, uint _offset) internal pure returns (int) { bytes memory _baseBytes = bytes(_base); bytes memory _valueBytes = bytes(_value); assert(_valueBytes.length == 1); for (uint i = _offset; i < _baseBytes.length; i++) { if (_baseBytes[i] == _valueBytes[0]) { return int(i); } } return -1; } /** * Length * * Returns the length of the specified string * * @param _base When being used for a data type this is the extended object * otherwise this is the string to be measured * @return uint The length of the passed string */ function length(string memory _base) internal pure returns (uint) { bytes memory _baseBytes = bytes(_base); return _baseBytes.length; } /** * Sub String * * Extracts the beginning part of a string based on the desired length * * @param _base When being used for a data type this is the extended object * otherwise this is the string that will be used for * extracting the sub string from * @param _length The length of the sub string to be extracted from the base * @return string The extracted sub string */ function substring(string memory _base, int _length) internal pure returns (string memory) { return _substring(_base, _length, 0); } /** * Sub String * * Extracts the part of a string based on the desired length and offset. The * offset and length must not exceed the lenth of the base string. * * @param _base When being used for a data type this is the extended object * otherwise this is the string that will be used for * extracting the sub string from * @param _length The length of the sub string to be extracted from the base * @param _offset The starting point to extract the sub string from * @return string The extracted sub string */ function _substring(string memory _base, int _length, int _offset) internal pure returns (string memory) { bytes memory _baseBytes = bytes(_base); assert(uint(_offset + _length) <= _baseBytes.length); string memory _tmp = new string(uint(_length)); bytes memory _tmpBytes = bytes(_tmp); uint j = 0; for (uint i = uint(_offset); i < uint(_offset + _length); i++) { _tmpBytes[j++] = _baseBytes[i]; } return string(_tmpBytes); } function split(string memory _base, string memory _value) internal pure returns (string[] memory splitArr) { bytes memory _baseBytes = bytes(_base); uint _offset = 0; uint _splitsCount = 1; while (_offset < _baseBytes.length - 1) { int _limit = _indexOf(_base, _value, _offset); if (_limit == -1) break; else { _splitsCount++; _offset = uint(_limit) + 1; } } splitArr = new string[](_splitsCount); _offset = 0; _splitsCount = 0; while (_offset < _baseBytes.length - 1) { int _limit = _indexOf(_base, _value, _offset); if (_limit == - 1) { _limit = int(_baseBytes.length); } string memory _tmp = new string(uint(_limit) - _offset); bytes memory _tmpBytes = bytes(_tmp); uint j = 0; for (uint i = _offset; i < uint(_limit); i++) { _tmpBytes[j++] = _baseBytes[i]; } _offset = uint(_limit) + 1; splitArr[_splitsCount++] = string(_tmpBytes); } return splitArr; } /** * Compare To * * Compares the characters of two strings, to ensure that they have an * identical footprint * * @param _base When being used for a data type this is the extended object * otherwise this is the string base to compare against * @param _value The string the base is being compared to * @return bool Simply notates if the two string have an equivalent */ function compareTo(string memory _base, string memory _value) internal pure returns (bool) { bytes memory _baseBytes = bytes(_base); bytes memory _valueBytes = bytes(_value); if (_baseBytes.length != _valueBytes.length) { return false; } for (uint i = 0; i < _baseBytes.length; i++) { if (_baseBytes[i] != _valueBytes[i]) { return false; } } return true; } /** * Compare To Ignore Case (High gas cost) * * Compares the characters of two strings, converting them to the same case * where applicable to alphabetic characters to distinguish if the values * match. * * @param _base When being used for a data type this is the extended object * otherwise this is the string base to compare against * @param _value The string the base is being compared to * @return bool Simply notates if the two string have an equivalent value * discarding case */ function compareToIgnoreCase(string memory _base, string memory _value) internal pure returns (bool) { bytes memory _baseBytes = bytes(_base); bytes memory _valueBytes = bytes(_value); if (_baseBytes.length != _valueBytes.length) { return false; } for (uint i = 0; i < _baseBytes.length; i++) { if (_baseBytes[i] != _valueBytes[i] && _upper(_baseBytes[i]) != _upper(_valueBytes[i])) { return false; } } return true; } /** * Upper * * Converts all the values of a string to their corresponding upper case * value. * * @param _base When being used for a data type this is the extended object * otherwise this is the string base to convert to upper case * @return string */ function upper(string memory _base) internal pure returns (string memory) { bytes memory _baseBytes = bytes(_base); for (uint i = 0; i < _baseBytes.length; i++) { _baseBytes[i] = _upper(_baseBytes[i]); } return string(_baseBytes); } /** * Lower * * Converts all the values of a string to their corresponding lower case * value. * * @param _base When being used for a data type this is the extended object * otherwise this is the string base to convert to lower case * @return string */ function lower(string memory _base) internal pure returns (string memory) { bytes memory _baseBytes = bytes(_base); for (uint i = 0; i < _baseBytes.length; i++) { _baseBytes[i] = _lower(_baseBytes[i]); } return string(_baseBytes); } /** * Upper * * Convert an alphabetic character to upper case and return the original * value when not alphabetic * * @param _b1 The byte to be converted to upper case * @return bytes1 The converted value if the passed value was alphabetic * and in a lower case otherwise returns the original value */ function _upper(bytes1 _b1) private pure returns (bytes1) { if (_b1 >= 0x61 && _b1 <= 0x7A) { return bytes1(uint8(_b1) - 32); } return _b1; } /** * Lower * * Convert an alphabetic character to lower case and return the original * value when not alphabetic * * @param _b1 The byte to be converted to lower case * @return bytes1 The converted value if the passed value was alphabetic * and in a upper case otherwise returns the original value */ function _lower(bytes1 _b1) private pure returns (bytes1) { if (_b1 >= 0x41 && _b1 <= 0x5A) { return bytes1(uint8(_b1) + 32); } return _b1; } } library Address { /** * @dev Returns true if `account` is a contract. * * This test is non-exhaustive, and there may be false-negatives: during the * execution of a contract's constructor, its address will be reported as * not containing a contract. * * > It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } interface ICallistoNFT { event NewBid (uint256 indexed tokenID, uint256 indexed bidAmount, bytes bidData); event TokenTrade (uint256 indexed tokenID, address indexed new_owner, address indexed previous_owner, uint256 priceInWEI); event Transfer (address indexed from, address indexed to, uint256 indexed tokenId); event TransferData (bytes data); struct Properties { // In this example properties of the given NFT are stored // in a dynamically sized array of strings // properties can be re-defined for any specific info // that a particular NFT is intended to store. /* Properties could look like this: bytes property1; bytes property2; address property3; */ string[] properties; } function name() external view returns (string memory); function symbol() external view returns (string memory); function standard() external view returns (string memory); function balanceOf(address _who) external view returns (uint256); function ownerOf(uint256 _tokenId) external view returns (address); function transfer(address _to, uint256 _tokenId, bytes calldata _data) external returns (bool); function silentTransfer(address _to, uint256 _tokenId) external returns (bool); function priceOf(uint256 _tokenId) external view returns (uint256); function bidOf(uint256 _tokenId) external view returns (uint256 price, address payable bidder, uint256 timestamp); function getTokenProperties(uint256 _tokenId) external view returns (Properties memory); function setBid(uint256 _tokenId, bytes calldata _data) payable external; // bid amount is defined by msg.value function setPrice(uint256 _tokenId, uint256 _amountInWEI, bytes calldata _data) external; function withdrawBid(uint256 _tokenId) external returns (bool); function getUserContent(uint256 _tokenId) external view returns (string memory _content); function setUserContent(uint256 _tokenId, string calldata _content) external returns (bool); } abstract contract NFTReceiver { function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external virtual returns(bytes4); } // ExtendedNFT is a version of the CallistoNFT standard token // that implements a set of function for NFT content management contract ExtendedNFT is ICallistoNFT, ReentrancyGuard { using Strings for string; using Address for address; mapping (uint256 => Properties) private _tokenProperties; mapping (uint32 => Fee) public feeLevels; // level # => (fee receiver, fee percentage) uint256 public bidLock = 1 days; // Time required for a bid to become withdrawable. struct Bid { address payable bidder; uint256 amountInWEI; uint256 timestamp; } struct Fee { address payable feeReceiver; uint256 feePercentage; // Will be divided by 100000 during calculations // feePercentage of 100 means 0.1% fee // feePercentage of 2500 means 2.5% fee } mapping (uint256 => uint256) private _asks; // tokenID => price of this token (in WEI) mapping (uint256 => Bid) private _bids; // tokenID => price of this token (in WEI) mapping (uint256 => uint32) internal _tokenFeeLevels; // tokenID => level ID / 0 by default uint256 public next_mint_id; // Token name string internal _name; // Token symbol string internal _symbol; // Mapping from token ID to owner address mapping(uint256 => address) internal _owners; // Mapping owner address to token count mapping(address => uint256) internal _balances; // Reward is always paid based on BID modifier checkTrade(uint256 _tokenId, bytes calldata _data) { _; (uint256 _bid, address payable _bidder,) = bidOf(_tokenId); if(priceOf(_tokenId) > 0 && priceOf(_tokenId) <= _bid) { uint256 _reward = _bid - _claimFee(_bid, _tokenId); emit TokenTrade(_tokenId, _bidder, ownerOf(_tokenId), _reward); bool sent = payable(ownerOf(_tokenId)).send(_reward); //bytes calldata _empty; delete _bids[_tokenId]; delete _asks[_tokenId]; _transfer(ownerOf(_tokenId), _bidder, _tokenId, _data); } } function standard() public view virtual override returns (string memory) { return "CallistoNFT"; } function mint() internal returns (uint256 _mintedId) { _safeMint(msg.sender, next_mint_id); _mintedId = next_mint_id; next_mint_id++; _configureNFT(_mintedId); } function priceOf(uint256 _tokenId) public view virtual override returns (uint256) { address owner = _owners[_tokenId]; require(owner != address(0), "NFT: owner query for nonexistent token"); return _asks[_tokenId]; } function bidOf(uint256 _tokenId) public view virtual override returns (uint256 price, address payable bidder, uint256 timestamp) { address owner = _owners[_tokenId]; require(owner != address(0), "NFT: owner query for nonexistent token"); return (_bids[_tokenId].amountInWEI, _bids[_tokenId].bidder, _bids[_tokenId].timestamp); } function getTokenProperties(uint256 _tokenId) public view virtual override returns (Properties memory) { return _tokenProperties[_tokenId]; } function getTokenProperty(uint256 _tokenId, uint256 _propertyId) public view virtual returns (string memory) { return _tokenProperties[_tokenId].properties[_propertyId]; } function getUserContent(uint256 _tokenId) public view virtual override returns (string memory _content) { return (_tokenProperties[_tokenId].properties[0]); } function setUserContent(uint256 _tokenId, string calldata _content) public virtual override returns (bool success) { require(msg.sender == ownerOf(_tokenId), "NFT: only owner can change NFT content"); _tokenProperties[_tokenId].properties[0] = _content; return true; } function _addPropertyWithContent(uint256 _tokenId, string calldata _content) internal { // Check permission criteria _tokenProperties[_tokenId].properties.push(_content); } function _modifyProperty(uint256 _tokenId, uint256 _propertyId, string calldata _content) internal { _tokenProperties[_tokenId].properties[_propertyId] = _content; } function _appendProperty(uint256 _tokenId, uint256 _propertyId, string calldata _content) internal { _tokenProperties[_tokenId].properties[_propertyId] = _tokenProperties[_tokenId].properties[_propertyId].concat(_content); } function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "NFT: balance query for the zero address"); return _balances[owner]; } function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "NFT: owner query for nonexistent token"); return owner; } // Price == 0, "NFT not on sale" // Price > 0, "NFT on sale" function setPrice(uint256 _tokenId, uint256 _amountInWEI, bytes calldata _data) checkTrade(_tokenId, _data) public virtual override nonReentrant { require(ownerOf(_tokenId) == msg.sender, "Setting asks is only allowed for owned NFTs!"); _asks[_tokenId] = _amountInWEI; } function setBid(uint256 _tokenId, bytes calldata _data) payable checkTrade(_tokenId, _data) public virtual override nonReentrant { (uint256 _previousBid, address payable _previousBidder, ) = bidOf(_tokenId); require(msg.value > _previousBid, "New bid must exceed the existing one"); uint256 _bid; // Return previous bid if the current one exceeds it. if(_previousBid != 0) { bool sent = _previousBidder.send(_previousBid); } // Refund overpaid amount if price is greater than 0 if (priceOf(_tokenId) < msg.value && priceOf(_tokenId) > 0) { _bid = priceOf(_tokenId); } else { _bid = msg.value; } _bids[_tokenId].amountInWEI = _bid; _bids[_tokenId].bidder = payable(msg.sender); _bids[_tokenId].timestamp = block.timestamp; emit NewBid(_tokenId, _bid, _data); // Send back overpaid amount. // WARNING: Creates possibility for reentrancy. if (priceOf(_tokenId) < msg.value && priceOf(_tokenId) > 0) { bool sent = payable(msg.sender).send(msg.value - priceOf(_tokenId)); } } function withdrawBid(uint256 _tokenId) public virtual override nonReentrant returns (bool) { (uint256 _bid, address payable _bidder, uint256 _timestamp) = bidOf(_tokenId); require(msg.sender == _bidder, "Can not withdraw someone elses bid"); require(block.timestamp > _timestamp + bidLock, "Bid is time-locked"); bool sent = _bidder.send(_bid); delete _bids[_tokenId]; return true; } function name() public view virtual override returns (string memory) { return _name; } function symbol() public view virtual override returns (string memory) { return _symbol; } function transfer(address _to, uint256 _tokenId, bytes calldata _data) public override returns (bool) { _transfer(msg.sender, _to, _tokenId, _data); emit TransferData(_data); return true; } function silentTransfer(address _to, uint256 _tokenId) public override returns (bool) { require(ExtendedNFT.ownerOf(_tokenId) == msg.sender, "NFT: transfer of token that is not own"); require(_to != address(0), "NFT: transfer to the zero address"); _asks[_tokenId] = 0; // Zero out price on transfer // When a user transfers the NFT to another user // it does not automatically mean that the new owner // would like to sell this NFT at a price // specified by the previous owner. // However bids persist regardless of token transfers // because we assume that the bidder still wants to buy the NFT // no matter from whom. _beforeTokenTransfer(msg.sender, _to, _tokenId); _balances[msg.sender] -= 1; _balances[_to] += 1; _owners[_tokenId] = _to; emit Transfer(msg.sender, _to, _tokenId); return true; } function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } function _claimFee(uint256 _amountFrom, uint256 _tokenId) internal returns (uint256) { uint32 _level = _tokenFeeLevels[_tokenId]; address _feeReceiver = feeLevels[_level].feeReceiver; uint256 _feePercentage = feeLevels[_level].feePercentage; uint256 _feeAmount = _amountFrom * _feePercentage / 100000; bool sent = payable(_feeReceiver).send(_feeAmount); return _feeAmount; } function _safeMint( address to, uint256 tokenId ) internal virtual { _mint(to, tokenId); } function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "NFT: mint to the zero address"); require(!_exists(tokenId), "NFT: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); } function _burn(uint256 tokenId) internal virtual { address owner = ExtendedNFT.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); _balances[owner] -= 1; delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); } function _transfer( address from, address to, uint256 tokenId, bytes calldata data ) internal virtual { require(ExtendedNFT.ownerOf(tokenId) == from, "NFT: transfer of token that is not own"); require(to != address(0), "NFT: transfer to the zero address"); _asks[tokenId] = 0; // Zero out price on transfer // When a user transfers the NFT to another user // it does not automatically mean that the new owner // would like to sell this NFT at a price // specified by the previous owner. // However bids persist regardless of token transfers // because we assume that the bidder still wants to buy the NFT // no matter from whom. _beforeTokenTransfer(from, to, tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; if(to.isContract()) { NFTReceiver(to).onERC721Received(msg.sender, from, tokenId, data); } emit Transfer(from, to, tokenId); } function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} function _configureNFT(uint256 _tokenId) internal { if(_tokenProperties[_tokenId].properties.length == 0) { _tokenProperties[_tokenId].properties.push(""); } } } interface IClassifiedNFT is ICallistoNFT { function setClassForTokenID(uint256 _tokenID, uint256 _tokenClass) external; function addNewTokenClass(uint32 _feeLevel, string memory _property) external; function addTokenClassProperties(uint256 _propertiesCount, uint256 classId) external; function modifyClassProperty(uint256 _classID, uint256 _propertyID, string memory _content) external; function getClassProperty(uint256 _classID, uint256 _propertyID) external view returns (string memory); function addClassProperty(uint256 _classID) external; function getClassProperties(uint256 _classID) external view returns (string[] memory); function getClassForTokenID(uint256 _tokenID) external view returns (uint256); function getClassPropertiesForTokenID(uint256 _tokenID) external view returns (string[] memory); function getClassPropertyForTokenID(uint256 _tokenID, uint256 _propertyID) external view returns (string memory); function mintWithClass(uint256 classId) external returns (uint256 _newTokenID); function appendClassProperty(uint256 _classID, uint256 _propertyID, string memory _content) external; } abstract contract ClassifiedNFT is MinterRole, ExtendedNFT, IClassifiedNFT { using Strings for string; mapping (uint256 => string[]) public class_properties; mapping (uint256 => uint32) public class_feeLevel; mapping (uint256 => uint256) public token_classes; uint256 public nextClassIndex = 0; mapping (address => bool) public classAdmins; modifier onlyExistingClasses(uint256 classId) { require(classId < nextClassIndex, "Queried class does not exist"); _; } modifier onlyClassAdmin() { require(classAdmins[_msgSender()], "ClassifiedNFT: caller is not the Class Admin"); _; } function classAdmin (address _newClassAdmin, bool _enable) public onlyOwner { classAdmins[_newClassAdmin] = _enable; } function setClassForTokenID(uint256 _tokenID, uint256 _tokenClass) public onlyOwner override { token_classes[_tokenID] = _tokenClass; } function addNewTokenClass(uint32 _feeLevel, string memory _property) public onlyClassAdmin override { class_properties[nextClassIndex].push(_property); class_feeLevel[nextClassIndex] = _feeLevel; // Configures who will receive fees from this class of NFTs // Zero sets fees to default address and percentage. nextClassIndex++; } function addTokenClassProperties(uint256 _propertiesCount, uint256 classId) public onlyClassAdmin override { for (uint i = 0; i < _propertiesCount; i++) { class_properties[classId].push(""); } } function modifyClassProperty(uint256 _classID, uint256 _propertyID, string memory _content) public onlyClassAdmin onlyExistingClasses(_classID) override { class_properties[_classID][_propertyID] = _content; } function getClassProperty(uint256 _classID, uint256 _propertyID) public view onlyExistingClasses(_classID) override returns (string memory) { return class_properties[_classID][_propertyID]; } function addClassProperty(uint256 _classID) public onlyClassAdmin onlyExistingClasses(_classID) override { class_properties[_classID].push(""); } function addClassPropertyWithContent(uint256 _classID, string memory _property) public onlyClassAdmin onlyExistingClasses(_classID) { class_properties[_classID].push(_property); } function getClassProperties(uint256 _classID) public view onlyExistingClasses(_classID) override returns (string[] memory) { return class_properties[_classID]; } function getClassForTokenID(uint256 _tokenID) public view onlyExistingClasses(token_classes[_tokenID]) override returns (uint256) { return token_classes[_tokenID]; } function getClassPropertiesForTokenID(uint256 _tokenID) public view onlyExistingClasses(token_classes[_tokenID]) override returns (string[] memory) { return class_properties[token_classes[_tokenID]]; } function getClassPropertyForTokenID(uint256 _tokenID, uint256 _propertyID) public view onlyExistingClasses(token_classes[_tokenID]) override returns (string memory) { return class_properties[token_classes[_tokenID]][_propertyID]; } function mintWithClass(uint256 classId) public onlyExistingClasses(classId) onlyMinter override returns (uint256 _newTokenID) { //_mint(to, tokenId); _newTokenID = mint(); token_classes[_newTokenID] = classId; _tokenFeeLevels[_newTokenID] = class_feeLevel[classId]; } function appendClassProperty(uint256 _classID, uint256 _propertyID, string memory _content) public onlyClassAdmin onlyExistingClasses(_classID) override { class_properties[_classID][_propertyID] = class_properties[_classID][_propertyID].concat(_content); } } contract ArtefinNFT is ExtendedNFT, ClassifiedNFT { function initialize(string memory name_, string memory symbol_, uint256 _defaultFee) external { require(_owner == address(0), "Already initialized"); _owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); bidLock = 1 days; _name = name_; _symbol = symbol_; feeLevels[0].feeReceiver = payable(msg.sender); feeLevels[0].feePercentage = _defaultFee; } function setFeeLevel(uint32 _levelIndex, address _feeReceiver, uint256 _feePercentage) public onlyOwner { feeLevels[_levelIndex].feeReceiver = payable(_feeReceiver); feeLevels[_levelIndex].feePercentage = _feePercentage; } function setFeeLevelForToken(uint256 _tokenId, uint32 _feeLevel) public onlyOwner { _tokenFeeLevels[_tokenId] = _feeLevel; } function modifyClassFeeLevel(uint256 _classId, uint32 _feeLevel) public onlyOwner { class_feeLevel[_classId] = _feeLevel; } function addPropertyWithContent(uint256 _tokenId, string calldata _content) public /* onlyOwner or Minter */ { require(owner() == msg.sender || minter_role[msg.sender], "Ownable: caller is not the owner"); _addPropertyWithContent( _tokenId, _content); } function modifyProperty(uint256 _tokenId, uint256 _propertyId, string calldata _content) public onlyOwner { _modifyProperty(_tokenId, _propertyId, _content); } function appendProperty(uint256 _tokenId, uint256 _propertyId, string calldata _content) public onlyOwner { _appendProperty(_tokenId, _propertyId, _content); } }
Contract ABI
[{"type":"event","name":"NewBid","inputs":[{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"uint256","name":"bidAmount","internalType":"uint256","indexed":true},{"type":"bytes","name":"bidData","internalType":"bytes","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":"TokenTrade","inputs":[{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"address","name":"new_owner","internalType":"address","indexed":true},{"type":"address","name":"previous_owner","internalType":"address","indexed":true},{"type":"uint256","name":"priceInWEI","internalType":"uint256","indexed":false}],"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":"event","name":"TransferData","inputs":[{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addClassProperty","inputs":[{"type":"uint256","name":"_classID","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addClassPropertyWithContent","inputs":[{"type":"uint256","name":"_classID","internalType":"uint256"},{"type":"string","name":"_property","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addNewTokenClass","inputs":[{"type":"uint32","name":"_feeLevel","internalType":"uint32"},{"type":"string","name":"_property","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addPropertyWithContent","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"string","name":"_content","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addTokenClassProperties","inputs":[{"type":"uint256","name":"_propertiesCount","internalType":"uint256"},{"type":"uint256","name":"classId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"appendClassProperty","inputs":[{"type":"uint256","name":"_classID","internalType":"uint256"},{"type":"uint256","name":"_propertyID","internalType":"uint256"},{"type":"string","name":"_content","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"appendProperty","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_propertyId","internalType":"uint256"},{"type":"string","name":"_content","internalType":"string"}]},{"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":"uint256","name":"","internalType":"uint256"}],"name":"bidLock","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price","internalType":"uint256"},{"type":"address","name":"bidder","internalType":"address payable"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"bidOf","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"classAdmin","inputs":[{"type":"address","name":"_newClassAdmin","internalType":"address"},{"type":"bool","name":"_enable","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"classAdmins","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"class_feeLevel","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"class_properties","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"feeReceiver","internalType":"address payable"},{"type":"uint256","name":"feePercentage","internalType":"uint256"}],"name":"feeLevels","inputs":[{"type":"uint32","name":"","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getClassForTokenID","inputs":[{"type":"uint256","name":"_tokenID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string[]","name":"","internalType":"string[]"}],"name":"getClassProperties","inputs":[{"type":"uint256","name":"_classID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string[]","name":"","internalType":"string[]"}],"name":"getClassPropertiesForTokenID","inputs":[{"type":"uint256","name":"_tokenID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"getClassProperty","inputs":[{"type":"uint256","name":"_classID","internalType":"uint256"},{"type":"uint256","name":"_propertyID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"getClassPropertyForTokenID","inputs":[{"type":"uint256","name":"_tokenID","internalType":"uint256"},{"type":"uint256","name":"_propertyID","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct ICallistoNFT.Properties","components":[{"type":"string[]","name":"properties","internalType":"string[]"}]}],"name":"getTokenProperties","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"getTokenProperty","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_propertyId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"_content","internalType":"string"}],"name":"getUserContent","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"string","name":"name_","internalType":"string"},{"type":"string","name":"symbol_","internalType":"string"},{"type":"uint256","name":"_defaultFee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_newTokenID","internalType":"uint256"}],"name":"mintWithClass","inputs":[{"type":"uint256","name":"classId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"minter_role","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"modifyClassFeeLevel","inputs":[{"type":"uint256","name":"_classId","internalType":"uint256"},{"type":"uint32","name":"_feeLevel","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"modifyClassProperty","inputs":[{"type":"uint256","name":"_classID","internalType":"uint256"},{"type":"uint256","name":"_propertyID","internalType":"uint256"},{"type":"string","name":"_content","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"modifyProperty","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_propertyId","internalType":"uint256"},{"type":"string","name":"_content","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nextClassIndex","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"next_mint_id","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":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"priceOf","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"setBid","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setClassForTokenID","inputs":[{"type":"uint256","name":"_tokenID","internalType":"uint256"},{"type":"uint256","name":"_tokenClass","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeLevel","inputs":[{"type":"uint32","name":"_levelIndex","internalType":"uint32"},{"type":"address","name":"_feeReceiver","internalType":"address"},{"type":"uint256","name":"_feePercentage","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeLevelForToken","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint32","name":"_feeLevel","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinterRole","inputs":[{"type":"address","name":"_who","internalType":"address"},{"type":"bool","name":"_status","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPrice","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_amountInWEI","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"success","internalType":"bool"}],"name":"setUserContent","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"string","name":"_content","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"silentTransfer","inputs":[{"type":"address","name":"_to","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"standard","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"token_classes","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"_to","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"withdrawBid","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]}]
Contract Creation Code
0x608060405262015180600555600060115534801561001c57600080fd5b506001600255613cf3806100316000396000f3fe60806040526004361061031e5760003560e01c806370a08231116101a5578063b9186d7d116100ec578063cb177b1e11610095578063d75d1e661161006f578063d75d1e66146109a7578063e29fb036146109ef578063e647005914610a05578063f2fde38b14610a2557600080fd5b8063cb177b1e14610937578063d29f165214610957578063d2b327ad1461097757600080fd5b8063be671058116100c6578063be671058146108ca578063c1940f1b146108ea578063c98e0c3c1461091757600080fd5b8063b9186d7d1461086a578063bb0537171461088a578063be45fd62146108aa57600080fd5b80638da5cb5b1161014e57806395d89b411161012857806395d89b41146108155780639de4792e1461082a578063b119490e1461084a57600080fd5b80638da5cb5b146107c15780638e39e18c146107df57806391100695146107ff57600080fd5b806378317f3f1161017f57806378317f3f146107615780637ab56e521461078157806380483a6a146107a157600080fd5b806370a08231146106cf57806373baa651146106ef57806374c29ce31461070257600080fd5b80633e0bb78311610269578063543dc7fa11610212578063648fbe40116101ec578063648fbe401461064c578063649ccc141461066c57806369a13712146106af57600080fd5b8063543dc7fa146105ae5780635a3b7e42146105ce5780636352211e1461061457600080fd5b80634c1720a4116102435780634c1720a4146105315780634edea11114610551578063510910bb1461057e57600080fd5b80633e0bb783146104c45780634774d93f146104e45780634bb2ddd41461050457600080fd5b8063290e008c116102cb5780633add5fa1116102a55780633add5fa1146104645780633c65b3eb146104845780633d8073f1146104a457600080fd5b8063290e008c146104045780632a6d3f44146104245780633054d9cb1461044457600080fd5b80631d734c8f116102fc5780631d734c8f1461039e5780631f38e654146103c257806325498c75146103e457600080fd5b806302ff368a1461032357806306fdde03146103595780630eaaf4c81461036e575b600080fd5b34801561032f57600080fd5b5061034361033e3660046133e1565b610a45565b6040516103509190613440565b60405180910390f35b34801561036557600080fd5b50610343610aff565b34801561037a57600080fd5b5061038e6103893660046133e1565b610b91565b6040519015158152602001610350565b3480156103aa57600080fd5b506103b460115481565b604051908152602001610350565b3480156103ce57600080fd5b506103e26103dd36600461345a565b610d3b565b005b3480156103f057600080fd5b506103e26103ff366004613538565b610da7565b34801561041057600080fd5b506103e261041f3660046135cf565b610e82565b34801561043057600080fd5b5061038e61043f3660046135cf565b610f15565b34801561045057600080fd5b506103e261045f36600461361b565b610fe9565b34801561047057600080fd5b506103e261047f36600461366b565b6110ef565b34801561049057600080fd5b506103b461049f3660046133e1565b61115b565b3480156104b057600080fd5b506103e26104bf36600461366b565b61125f565b3480156104d057600080fd5b506103436104df36600461345a565b611483565b3480156104f057600080fd5b506103e26104ff36600461361b565b61153c565b34801561051057600080fd5b5061052461051f3660046133e1565b6116e9565b6040516103509190613713565b34801561053d57600080fd5b5061034361054c36600461345a565b611839565b34801561055d57600080fd5b5061057161056c3660046133e1565b611949565b6040516103509190613726565b34801561058a57600080fd5b5061038e610599366004613760565b60016020526000908152604090205460ff1681565b3480156105ba57600080fd5b506103b46105c93660046133e1565b611a3e565b3480156105da57600080fd5b5060408051808201909152600b81527f43616c6c6973746f4e46540000000000000000000000000000000000000000006020820152610343565b34801561062057600080fd5b5061063461062f3660046133e1565b611ab2565b6040516001600160a01b039091168152602001610350565b34801561065857600080fd5b506103e261066736600461377b565b611b2c565b34801561067857600080fd5b5061068c6106873660046133e1565b611bae565b604080519384526001600160a01b03909216602084015290820152606001610350565b3480156106bb57600080fd5b506103e26106ca3660046137a7565b611c55565b3480156106db57600080fd5b506103b46106ea366004613760565b611d43565b6103e26106fd3660046135cf565b611ddd565b34801561070e57600080fd5b5061074261071d3660046137d8565b600460205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b039093168352602083019190915201610350565b34801561076d57600080fd5b506103e261077c36600461377b565b612112565b34801561078d57600080fd5b5061034361079c36600461345a565b612194565b3480156107ad57600080fd5b506103e26107bc3660046133e1565b612253565b3480156107cd57600080fd5b506000546001600160a01b0316610634565b3480156107eb57600080fd5b506103e26107fa3660046137f3565b612351565b34801561080b57600080fd5b506103b460055481565b34801561082157600080fd5b506103436123e6565b34801561083657600080fd5b5061034361084536600461345a565b6123f5565b34801561085657600080fd5b506103e261086536600461382f565b612486565b34801561087657600080fd5b506103b46108853660046133e1565b61259f565b34801561089657600080fd5b506103e26108a536600461366b565b612627565b3480156108b657600080fd5b5061038e6108c536600461389c565b61268d565b3480156108d657600080fd5b506103e26108e536600461345a565b6126e0565b3480156108f657600080fd5b506103b46109053660046133e1565b60106020526000908152604090205481565b34801561092357600080fd5b5061038e6109323660046138de565b6127aa565b34801561094357600080fd5b506103e2610952366004613908565b61293b565b34801561096357600080fd5b506103e2610972366004613908565b6129c0565b34801561098357600080fd5b5061038e610992366004613760565b60126020526000908152604090205460ff1681565b3480156109b357600080fd5b506109da6109c23660046133e1565b600f6020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610350565b3480156109fb57600080fd5b506103b460095481565b348015610a1157600080fd5b50610524610a203660046133e1565b612a45565b348015610a3157600080fd5b506103e2610a40366004613760565b612b6e565b6000818152600360205260408120805460609290610a6557610a65613944565b906000526020600020018054610a7a9061395a565b80601f0160208091040260200160405190810160405280929190818152602001828054610aa69061395a565b8015610af35780601f10610ac857610100808354040283529160200191610af3565b820191906000526020600020905b815481529060010190602001808311610ad657829003601f168201915b50505050509050919050565b6060600a8054610b0e9061395a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b3a9061395a565b8015610b875780601f10610b5c57610100808354040283529160200191610b87565b820191906000526020600020905b815481529060010190602001808311610b6a57829003601f168201915b5050505050905090565b60006002805403610be95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002805560008080610bfa85611bae565b91945092509050336001600160a01b03831614610c7f5760405162461bcd60e51b815260206004820152602260248201527f43616e206e6f7420776974686472617720736f6d656f6e6520656c736573206260448201527f69640000000000000000000000000000000000000000000000000000000000006064820152608401610be0565b600554610c8c90826139a4565b4211610cda5760405162461bcd60e51b815260206004820152601260248201527f4269642069732074696d652d6c6f636b656400000000000000000000000000006044820152606401610be0565b6040516000906001600160a01b0384169085156108fc0290869084818181858888f150505060009788525050600760205250506040842080546001600160a01b03191681556001808201869055600291820195909555849055509192915050565b6000546001600160a01b03163314610d955760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b60009182526010602052604090912055565b3360009081526012602052604090205460ff16610e1b5760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b6011546000908152600e6020908152604082208054600181018255908352912001610e468282613a05565b50601180546000908152600f60205260408120805463ffffffff191663ffffffff861617905581549190610e7983613ac5565b91905055505050565b33610e956000546001600160a01b031690565b6001600160a01b03161480610eb957503360009081526001602052604090205460ff165b610f055760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b610f10838383612c50565b505050565b6000610f2084611ab2565b6001600160a01b0316336001600160a01b031614610fa65760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f6e6c79206f776e65722063616e206368616e6765204e4654206360448201527f6f6e74656e7400000000000000000000000000000000000000000000000000006064820152608401610be0565b600084815260036020526040812080548592859291610fc757610fc7613944565b906000526020600020019182610fde929190613ade565b506001949350505050565b3360009081526012602052604090205460ff1661105d5760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b8260115481106110af5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000848152600e602052604090208054839190859081106110d2576110d2613944565b9060005260206000200190816110e89190613a05565b5050505050565b6000546001600160a01b031633146111495760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b61115584848484612c79565b50505050565b60008160115481106111af5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b3360009081526001602052604090205460ff1661120e5760405162461bcd60e51b815260206004820152601460248201527f4d696e74657220726f6c652072657175697265640000000000000000000000006044820152606401610be0565b611216612cf2565b6000818152601060209081526040808320879055958252600f8152858220548383526008909152949020805463ffffffff191663ffffffff909516949094179093555090919050565b83828260028054036112b35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610be0565b60028055336112c188611ab2565b6001600160a01b03161461133d5760405162461bcd60e51b815260206004820152602c60248201527f53657474696e672061736b73206973206f6e6c7920616c6c6f77656420666f7260448201527f206f776e6564204e4654732100000000000000000000000000000000000000006064820152608401610be0565b600087815260066020526040812087905560016002558061135d85611bae565b5091509150600061136d8661259f565b11801561138257508161137f8661259f565b11155b156114785760006113938387612d24565b61139d9084613b9e565b90506113a886611ab2565b6001600160a01b0316826001600160a01b0316877fc9b9afd9684b23c6b22a41016c08e8954ac118220c0a52f00b8774c46580e9a3846040516113ed91815260200190565b60405180910390a4600061140087611ab2565b6001600160a01b03166108fc839081150290604051600060405180830381858888f160008c815260076020908152604080832080546001600160a01b03191681556001810184905560020183905560069091528120559450611475935061146c92508a9150611ab29050565b84898989612dab565b50505b505050505050505050565b600e602052816000526040600020818154811061149f57600080fd5b906000526020600020016000915091505080546114bb9061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546114e79061395a565b80156115345780601f1061150957610100808354040283529160200191611534565b820191906000526020600020905b81548152906001019060200180831161151757829003601f168201915b505050505081565b3360009081526012602052604090205460ff166115b05760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b8260115481106116025760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000848152600e6020526040902080546116c99184918690811061162857611628613944565b90600052602060002001805461163d9061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546116699061395a565b80156116b65780601f1061168b576101008083540402835291602001916116b6565b820191906000526020600020905b81548152906001019060200180831161169957829003601f168201915b5050505050612ff890919063ffffffff16565b6000858152600e602052604090208054859081106110d2576110d2613944565b60008181526010602052604090205460115460609190811061174d5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000838152601060209081526040808320548352600e825280832080548251818502810185019093528083529193909284015b8282101561182c57838290600052602060002001805461179f9061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546117cb9061395a565b80156118185780601f106117ed57610100808354040283529160200191611818565b820191906000526020600020905b8154815290600101906020018083116117fb57829003601f168201915b505050505081526020019060010190611780565b5050505091505b50919050565b606082601154811061188d5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000848152600e602052604090208054849081106118ad576118ad613944565b9060005260206000200180546118c29061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546118ee9061395a565b801561193b5780601f106119105761010080835404028352916020019161193b565b820191906000526020600020905b81548152906001019060200180831161191e57829003601f168201915b505050505091505092915050565b604080516020808201835260608252600084815260038252838120845181548085028201870187529381018481529495909491938593859285015b82821015611a305783829060005260206000200180546119a39061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546119cf9061395a565b8015611a1c5780601f106119f157610100808354040283529160200191611a1c565b820191906000526020600020905b8154815290600101906020018083116119ff57829003601f168201915b505050505081526020019060010190611984565b505050915250909392505050565b6000818152601060205260408120546011548110611a9e5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b505060009081526010602052604090205490565b6000818152600c60205260408120546001600160a01b031680611b265760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610be0565b92915050565b6000546001600160a01b03163314611b865760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b600091825260086020526040909120805463ffffffff191663ffffffff909216919091179055565b6000818152600c6020526040812054819081906001600160a01b031680611c265760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610be0565b5050506000918252506007602052604090206001810154815460029092015490926001600160a01b0390921691565b3360009081526012602052604090205460ff16611cc95760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b816011548110611d1b5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000838152600e60209081526040822080546001810182559083529120016111558382613a05565b60006001600160a01b038216611dc15760405162461bcd60e51b815260206004820152602760248201527f4e46543a2062616c616e636520717565727920666f7220746865207a65726f2060448201527f61646472657373000000000000000000000000000000000000000000000000006064820152608401610be0565b506001600160a01b03166000908152600d602052604090205490565b8282826002805403611e315760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610be0565b60028055600080611e4188611bae565b5091509150813411611eba5760405162461bcd60e51b8152602060048201526024808201527f4e657720626964206d7573742065786365656420746865206578697374696e6760448201527f206f6e65000000000000000000000000000000000000000000000000000000006064820152608401610be0565b60008215611eeb576040516000906001600160a01b0384169085156108fc0290869084818181858888f15050505050505b34611ef58a61259f565b108015611f0a57506000611f088a61259f565b115b15611f1f57611f188961259f565b9050611f22565b50345b600089815260076020526040908190206001810183905580546001600160a01b03191633178155426002909101555181908a907f223d0d5db4846341da7a5cc902b1a7c597e63b6c73b1c6267dc931d290c7affb90611f84908c908c90613bda565b60405180910390a334611f968a61259f565b108015611fab57506000611fa98a61259f565b115b15611fe2576000336108fc611fbf8c61259f565b611fc99034613b9e565b6040518115909202916000818181858888f15050505050505b5050600160025550600080611ff685611bae565b509150915060006120068661259f565b11801561201b5750816120188661259f565b11155b1561210857600061202c8387612d24565b6120369084613b9e565b905061204186611ab2565b6001600160a01b0316826001600160a01b0316877fc9b9afd9684b23c6b22a41016c08e8954ac118220c0a52f00b8774c46580e9a38460405161208691815260200190565b60405180910390a4600061209987611ab2565b6001600160a01b03166108fc839081150290604051600060405180830381858888f160008c815260076020908152604080832080546001600160a01b03191681556001810184905560020183905560069091528120559450612105935061146c92508a9150611ab29050565b50505b5050505050505050565b6000546001600160a01b0316331461216c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b6000918252600f6020526040909120805463ffffffff191663ffffffff909216919091179055565b6000828152600360205260409020805460609190839081106121b8576121b8613944565b9060005260206000200180546121cd9061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546121f99061395a565b80156122465780601f1061221b57610100808354040283529160200191612246565b820191906000526020600020905b81548152906001019060200180831161222957829003601f168201915b5050505050905092915050565b3360009081526012602052604090205460ff166122c75760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b8060115481106123195760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000828152600e602090815260408083208054600181018255908452828420825193840190925292825290910190610f109082613a05565b6000546001600160a01b031633146123ab5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b63ffffffff909216600090815260046020526040902080546001600160a01b039092166001600160a01b031990921691909117815560010155565b6060600b8054610b0e9061395a565b6000828152601060205260409020546011546060919081106124595760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000848152601060209081526040808320548352600e90915290208054849081106118ad576118ad613944565b6000546001600160a01b0316156124df5760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610be0565b600080546001600160a01b0319163390811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a362015180600555600a6125318482613a05565b50600b61253e8382613a05565b506000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec80546001600160a01b031916331790557f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed555050565b6000818152600c60205260408120546001600160a01b0316806126135760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610be0565b505060009081526006602052604090205490565b6000546001600160a01b031633146126815760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b611155848484846131b9565b600061269c3386868686612dab565b7f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad97683836040516126cd929190613bda565b60405180910390a1506001949350505050565b3360009081526012602052604090205460ff166127545760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b60005b82811015610f10576000828152600e6020908152604080832080546001810182559084528284208251938401909252928252909101906127979082613a05565b50806127a281613ac5565b915050612757565b6000336127b683611ab2565b6001600160a01b03161461281b5760405162461bcd60e51b815260206004820152602660248201527f4e46543a207472616e73666572206f6620746f6b656e2074686174206973206e60448201526537ba1037bbb760d11b6064820152608401610be0565b6001600160a01b03831661287b5760405162461bcd60e51b815260206004820152602160248201527f4e46543a207472616e7366657220746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610be0565b600082815260066020526040812055336000908152600d602052604081208054600192906128aa908490613b9e565b90915550506001600160a01b0383166000908152600d602052604081208054600192906128d89084906139a4565b90915550506000828152600c602052604080822080546001600160a01b0319166001600160a01b0387169081179091559051849233917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9190a450600192915050565b6000546001600160a01b031633146129955760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b6001600160a01b03919091166000908152600160205260409020805460ff1916911515919091179055565b6000546001600160a01b03163314612a1a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b6001600160a01b03919091166000908152601260205260409020805460ff1916911515919091179055565b6060816011548110612a995760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000838152600e6020908152604080832080548251818502810185019093528083529193909284015b8282101561182c578382906000526020600020018054612ae19061395a565b80601f0160208091040260200160405190810160405280929190818152602001828054612b0d9061395a565b8015612b5a5780601f10612b2f57610100808354040283529160200191612b5a565b820191906000526020600020905b815481529060010190602001808311612b3d57829003601f168201915b505050505081526020019060010190612ac2565b6000546001600160a01b03163314612bc85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b6001600160a01b038116612c445760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610be0565b612c4d816131f4565b50565b600083815260036020908152604082208054600181018255908352912001611155828483613ade565b612cd282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525089815260036020526040902080549093508892508210905061162857611628613944565b60008581526003602052604090208054859081106110d2576110d2613944565b6000612d0033600954613244565b50600980549081906000612d1383613ac5565b9190505550612d2181613252565b90565b60008181526008602090815260408083205463ffffffff168084526004909252822080546001909101546001600160a01b039091169083620186a0612d698389613bee565b612d739190613c05565b90506000836001600160a01b03166108fc839081150290604051600060405180830381858888f150949b9a5050505050505050505050565b846001600160a01b0316612dbe84611ab2565b6001600160a01b031614612e235760405162461bcd60e51b815260206004820152602660248201527f4e46543a207472616e73666572206f6620746f6b656e2074686174206973206e60448201526537ba1037bbb760d11b6064820152608401610be0565b6001600160a01b038416612e835760405162461bcd60e51b815260206004820152602160248201527f4e46543a207472616e7366657220746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610be0565b6000838152600660205260408120556001600160a01b0385166000908152600d60205260408120805460019290612ebb908490613b9e565b90915550506001600160a01b0384166000908152600d60205260408120805460019290612ee99084906139a4565b90915550506000838152600c6020526040902080546001600160a01b0319166001600160a01b0386169081179091553b15612fb0576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063150b7a0290612f6b9033908990889088908890600401613c27565b6020604051808303816000875af1158015612f8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fae9190613c65565b505b82846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050565b80516060908390839061300d5761300d613ca7565b60008151835161301d91906139a4565b67ffffffffffffffff81111561303557613035613495565b6040519080825280601f01601f19166020018201604052801561305f576020820181803683370190505b509050806000805b85518210156131075785828151811061308257613082613944565b01602001517fff000000000000000000000000000000000000000000000000000000000000001683826130b481613ac5565b9350815181106130c6576130c6613944565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350816130ff81613ac5565b925050613067565b600091505b84518210156131ac5784828151811061312757613127613944565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016838261315981613ac5565b93508151811061316b5761316b613944565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350816131a481613ac5565b92505061310c565b5090979650505050505050565b6000848152600360205260409020805483918391869081106131dd576131dd613944565b9060005260206000200191826110e8929190613ade565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61324e828261329f565b5050565b6000818152600360205260408120549003612c4d576000818152600360209081526040808320805460018101825590845282842082519384019092529282529091019061324e9082613a05565b6001600160a01b0382166132f55760405162461bcd60e51b815260206004820152601d60248201527f4e46543a206d696e7420746f20746865207a65726f20616464726573730000006044820152606401610be0565b6000818152600c60205260409020546001600160a01b03161561335a5760405162461bcd60e51b815260206004820152601960248201527f4e46543a20746f6b656e20616c7265616479206d696e746564000000000000006044820152606401610be0565b6001600160a01b0382166000908152600d602052604081208054600192906133839084906139a4565b90915550506000818152600c602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000602082840312156133f357600080fd5b5035919050565b6000815180845260005b8181101561342057602081850181015186830182015201613404565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061345360208301846133fa565b9392505050565b6000806040838503121561346d57600080fd5b50508035926020909101359150565b803563ffffffff8116811461349057600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126134bc57600080fd5b813567ffffffffffffffff808211156134d7576134d7613495565b604051601f8301601f19908116603f011681019082821181831017156134ff576134ff613495565b8160405283815286602085880101111561351857600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561354b57600080fd5b6135548361347c565b9150602083013567ffffffffffffffff81111561357057600080fd5b61357c858286016134ab565b9150509250929050565b60008083601f84011261359857600080fd5b50813567ffffffffffffffff8111156135b057600080fd5b6020830191508360208285010111156135c857600080fd5b9250929050565b6000806000604084860312156135e457600080fd5b83359250602084013567ffffffffffffffff81111561360257600080fd5b61360e86828701613586565b9497909650939450505050565b60008060006060848603121561363057600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561365557600080fd5b613661868287016134ab565b9150509250925092565b6000806000806060858703121561368157600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156136a657600080fd5b6136b287828801613586565b95989497509550505050565b600081518084526020808501808196508360051b8101915082860160005b858110156137065782840389526136f48483516133fa565b988501989350908401906001016136dc565b5091979650505050505050565b60208152600061345360208301846136be565b602081526000825160208084015261374160408401826136be565b949350505050565b80356001600160a01b038116811461349057600080fd5b60006020828403121561377257600080fd5b61345382613749565b6000806040838503121561378e57600080fd5b8235915061379e6020840161347c565b90509250929050565b600080604083850312156137ba57600080fd5b82359150602083013567ffffffffffffffff81111561357057600080fd5b6000602082840312156137ea57600080fd5b6134538261347c565b60008060006060848603121561380857600080fd5b6138118461347c565b925061381f60208501613749565b9150604084013590509250925092565b60008060006060848603121561384457600080fd5b833567ffffffffffffffff8082111561385c57600080fd5b613868878388016134ab565b9450602086013591508082111561387e57600080fd5b5061388b868287016134ab565b925050604084013590509250925092565b600080600080606085870312156138b257600080fd5b6138bb85613749565b935060208501359250604085013567ffffffffffffffff8111156136a657600080fd5b600080604083850312156138f157600080fd5b6138fa83613749565b946020939093013593505050565b6000806040838503121561391b57600080fd5b61392483613749565b91506020830135801515811461393957600080fd5b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061396e57607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115611b2657611b2661398e565b601f821115610f1057600081815260208120601f850160051c810160208610156139de5750805b601f850160051c820191505b818110156139fd578281556001016139ea565b505050505050565b815167ffffffffffffffff811115613a1f57613a1f613495565b613a3381613a2d845461395a565b846139b7565b602080601f831160018114613a685760008415613a505750858301515b600019600386901b1c1916600185901b1785556139fd565b600085815260208120601f198616915b82811015613a9757888601518255948401946001909101908401613a78565b5085821015613ab55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060018201613ad757613ad761398e565b5060010190565b67ffffffffffffffff831115613af657613af6613495565b613b0a83613b04835461395a565b836139b7565b6000601f841160018114613b3e5760008515613b265750838201355b600019600387901b1c1916600186901b1783556110e8565b600083815260209020601f19861690835b82811015613b6f5786850135825560209485019460019092019101613b4f565b5086821015613b8c5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81810381811115611b2657611b2661398e565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b602081526000613741602083018486613bb1565b8082028115828204841417611b2657611b2661398e565b600082613c2257634e487b7160e01b600052601260045260246000fd5b500490565b60006001600160a01b03808816835280871660208401525084604083015260806060830152613c5a608083018486613bb1565b979650505050505050565b600060208284031215613c7757600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461345357600080fd5b634e487b7160e01b600052600160045260246000fdfea2646970667358221220b4439bf81c4d951e3cb2b6c85d9d2ca693125f0a4c08b56a6fbdbb5a58ac074a64736f6c63430008110033
Deployed ByteCode
0x60806040526004361061031e5760003560e01c806370a08231116101a5578063b9186d7d116100ec578063cb177b1e11610095578063d75d1e661161006f578063d75d1e66146109a7578063e29fb036146109ef578063e647005914610a05578063f2fde38b14610a2557600080fd5b8063cb177b1e14610937578063d29f165214610957578063d2b327ad1461097757600080fd5b8063be671058116100c6578063be671058146108ca578063c1940f1b146108ea578063c98e0c3c1461091757600080fd5b8063b9186d7d1461086a578063bb0537171461088a578063be45fd62146108aa57600080fd5b80638da5cb5b1161014e57806395d89b411161012857806395d89b41146108155780639de4792e1461082a578063b119490e1461084a57600080fd5b80638da5cb5b146107c15780638e39e18c146107df57806391100695146107ff57600080fd5b806378317f3f1161017f57806378317f3f146107615780637ab56e521461078157806380483a6a146107a157600080fd5b806370a08231146106cf57806373baa651146106ef57806374c29ce31461070257600080fd5b80633e0bb78311610269578063543dc7fa11610212578063648fbe40116101ec578063648fbe401461064c578063649ccc141461066c57806369a13712146106af57600080fd5b8063543dc7fa146105ae5780635a3b7e42146105ce5780636352211e1461061457600080fd5b80634c1720a4116102435780634c1720a4146105315780634edea11114610551578063510910bb1461057e57600080fd5b80633e0bb783146104c45780634774d93f146104e45780634bb2ddd41461050457600080fd5b8063290e008c116102cb5780633add5fa1116102a55780633add5fa1146104645780633c65b3eb146104845780633d8073f1146104a457600080fd5b8063290e008c146104045780632a6d3f44146104245780633054d9cb1461044457600080fd5b80631d734c8f116102fc5780631d734c8f1461039e5780631f38e654146103c257806325498c75146103e457600080fd5b806302ff368a1461032357806306fdde03146103595780630eaaf4c81461036e575b600080fd5b34801561032f57600080fd5b5061034361033e3660046133e1565b610a45565b6040516103509190613440565b60405180910390f35b34801561036557600080fd5b50610343610aff565b34801561037a57600080fd5b5061038e6103893660046133e1565b610b91565b6040519015158152602001610350565b3480156103aa57600080fd5b506103b460115481565b604051908152602001610350565b3480156103ce57600080fd5b506103e26103dd36600461345a565b610d3b565b005b3480156103f057600080fd5b506103e26103ff366004613538565b610da7565b34801561041057600080fd5b506103e261041f3660046135cf565b610e82565b34801561043057600080fd5b5061038e61043f3660046135cf565b610f15565b34801561045057600080fd5b506103e261045f36600461361b565b610fe9565b34801561047057600080fd5b506103e261047f36600461366b565b6110ef565b34801561049057600080fd5b506103b461049f3660046133e1565b61115b565b3480156104b057600080fd5b506103e26104bf36600461366b565b61125f565b3480156104d057600080fd5b506103436104df36600461345a565b611483565b3480156104f057600080fd5b506103e26104ff36600461361b565b61153c565b34801561051057600080fd5b5061052461051f3660046133e1565b6116e9565b6040516103509190613713565b34801561053d57600080fd5b5061034361054c36600461345a565b611839565b34801561055d57600080fd5b5061057161056c3660046133e1565b611949565b6040516103509190613726565b34801561058a57600080fd5b5061038e610599366004613760565b60016020526000908152604090205460ff1681565b3480156105ba57600080fd5b506103b46105c93660046133e1565b611a3e565b3480156105da57600080fd5b5060408051808201909152600b81527f43616c6c6973746f4e46540000000000000000000000000000000000000000006020820152610343565b34801561062057600080fd5b5061063461062f3660046133e1565b611ab2565b6040516001600160a01b039091168152602001610350565b34801561065857600080fd5b506103e261066736600461377b565b611b2c565b34801561067857600080fd5b5061068c6106873660046133e1565b611bae565b604080519384526001600160a01b03909216602084015290820152606001610350565b3480156106bb57600080fd5b506103e26106ca3660046137a7565b611c55565b3480156106db57600080fd5b506103b46106ea366004613760565b611d43565b6103e26106fd3660046135cf565b611ddd565b34801561070e57600080fd5b5061074261071d3660046137d8565b600460205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b039093168352602083019190915201610350565b34801561076d57600080fd5b506103e261077c36600461377b565b612112565b34801561078d57600080fd5b5061034361079c36600461345a565b612194565b3480156107ad57600080fd5b506103e26107bc3660046133e1565b612253565b3480156107cd57600080fd5b506000546001600160a01b0316610634565b3480156107eb57600080fd5b506103e26107fa3660046137f3565b612351565b34801561080b57600080fd5b506103b460055481565b34801561082157600080fd5b506103436123e6565b34801561083657600080fd5b5061034361084536600461345a565b6123f5565b34801561085657600080fd5b506103e261086536600461382f565b612486565b34801561087657600080fd5b506103b46108853660046133e1565b61259f565b34801561089657600080fd5b506103e26108a536600461366b565b612627565b3480156108b657600080fd5b5061038e6108c536600461389c565b61268d565b3480156108d657600080fd5b506103e26108e536600461345a565b6126e0565b3480156108f657600080fd5b506103b46109053660046133e1565b60106020526000908152604090205481565b34801561092357600080fd5b5061038e6109323660046138de565b6127aa565b34801561094357600080fd5b506103e2610952366004613908565b61293b565b34801561096357600080fd5b506103e2610972366004613908565b6129c0565b34801561098357600080fd5b5061038e610992366004613760565b60126020526000908152604090205460ff1681565b3480156109b357600080fd5b506109da6109c23660046133e1565b600f6020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610350565b3480156109fb57600080fd5b506103b460095481565b348015610a1157600080fd5b50610524610a203660046133e1565b612a45565b348015610a3157600080fd5b506103e2610a40366004613760565b612b6e565b6000818152600360205260408120805460609290610a6557610a65613944565b906000526020600020018054610a7a9061395a565b80601f0160208091040260200160405190810160405280929190818152602001828054610aa69061395a565b8015610af35780601f10610ac857610100808354040283529160200191610af3565b820191906000526020600020905b815481529060010190602001808311610ad657829003601f168201915b50505050509050919050565b6060600a8054610b0e9061395a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b3a9061395a565b8015610b875780601f10610b5c57610100808354040283529160200191610b87565b820191906000526020600020905b815481529060010190602001808311610b6a57829003601f168201915b5050505050905090565b60006002805403610be95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002805560008080610bfa85611bae565b91945092509050336001600160a01b03831614610c7f5760405162461bcd60e51b815260206004820152602260248201527f43616e206e6f7420776974686472617720736f6d656f6e6520656c736573206260448201527f69640000000000000000000000000000000000000000000000000000000000006064820152608401610be0565b600554610c8c90826139a4565b4211610cda5760405162461bcd60e51b815260206004820152601260248201527f4269642069732074696d652d6c6f636b656400000000000000000000000000006044820152606401610be0565b6040516000906001600160a01b0384169085156108fc0290869084818181858888f150505060009788525050600760205250506040842080546001600160a01b03191681556001808201869055600291820195909555849055509192915050565b6000546001600160a01b03163314610d955760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b60009182526010602052604090912055565b3360009081526012602052604090205460ff16610e1b5760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b6011546000908152600e6020908152604082208054600181018255908352912001610e468282613a05565b50601180546000908152600f60205260408120805463ffffffff191663ffffffff861617905581549190610e7983613ac5565b91905055505050565b33610e956000546001600160a01b031690565b6001600160a01b03161480610eb957503360009081526001602052604090205460ff165b610f055760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b610f10838383612c50565b505050565b6000610f2084611ab2565b6001600160a01b0316336001600160a01b031614610fa65760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f6e6c79206f776e65722063616e206368616e6765204e4654206360448201527f6f6e74656e7400000000000000000000000000000000000000000000000000006064820152608401610be0565b600084815260036020526040812080548592859291610fc757610fc7613944565b906000526020600020019182610fde929190613ade565b506001949350505050565b3360009081526012602052604090205460ff1661105d5760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b8260115481106110af5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000848152600e602052604090208054839190859081106110d2576110d2613944565b9060005260206000200190816110e89190613a05565b5050505050565b6000546001600160a01b031633146111495760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b61115584848484612c79565b50505050565b60008160115481106111af5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b3360009081526001602052604090205460ff1661120e5760405162461bcd60e51b815260206004820152601460248201527f4d696e74657220726f6c652072657175697265640000000000000000000000006044820152606401610be0565b611216612cf2565b6000818152601060209081526040808320879055958252600f8152858220548383526008909152949020805463ffffffff191663ffffffff909516949094179093555090919050565b83828260028054036112b35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610be0565b60028055336112c188611ab2565b6001600160a01b03161461133d5760405162461bcd60e51b815260206004820152602c60248201527f53657474696e672061736b73206973206f6e6c7920616c6c6f77656420666f7260448201527f206f776e6564204e4654732100000000000000000000000000000000000000006064820152608401610be0565b600087815260066020526040812087905560016002558061135d85611bae565b5091509150600061136d8661259f565b11801561138257508161137f8661259f565b11155b156114785760006113938387612d24565b61139d9084613b9e565b90506113a886611ab2565b6001600160a01b0316826001600160a01b0316877fc9b9afd9684b23c6b22a41016c08e8954ac118220c0a52f00b8774c46580e9a3846040516113ed91815260200190565b60405180910390a4600061140087611ab2565b6001600160a01b03166108fc839081150290604051600060405180830381858888f160008c815260076020908152604080832080546001600160a01b03191681556001810184905560020183905560069091528120559450611475935061146c92508a9150611ab29050565b84898989612dab565b50505b505050505050505050565b600e602052816000526040600020818154811061149f57600080fd5b906000526020600020016000915091505080546114bb9061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546114e79061395a565b80156115345780601f1061150957610100808354040283529160200191611534565b820191906000526020600020905b81548152906001019060200180831161151757829003601f168201915b505050505081565b3360009081526012602052604090205460ff166115b05760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b8260115481106116025760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000848152600e6020526040902080546116c99184918690811061162857611628613944565b90600052602060002001805461163d9061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546116699061395a565b80156116b65780601f1061168b576101008083540402835291602001916116b6565b820191906000526020600020905b81548152906001019060200180831161169957829003601f168201915b5050505050612ff890919063ffffffff16565b6000858152600e602052604090208054859081106110d2576110d2613944565b60008181526010602052604090205460115460609190811061174d5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000838152601060209081526040808320548352600e825280832080548251818502810185019093528083529193909284015b8282101561182c57838290600052602060002001805461179f9061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546117cb9061395a565b80156118185780601f106117ed57610100808354040283529160200191611818565b820191906000526020600020905b8154815290600101906020018083116117fb57829003601f168201915b505050505081526020019060010190611780565b5050505091505b50919050565b606082601154811061188d5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000848152600e602052604090208054849081106118ad576118ad613944565b9060005260206000200180546118c29061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546118ee9061395a565b801561193b5780601f106119105761010080835404028352916020019161193b565b820191906000526020600020905b81548152906001019060200180831161191e57829003601f168201915b505050505091505092915050565b604080516020808201835260608252600084815260038252838120845181548085028201870187529381018481529495909491938593859285015b82821015611a305783829060005260206000200180546119a39061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546119cf9061395a565b8015611a1c5780601f106119f157610100808354040283529160200191611a1c565b820191906000526020600020905b8154815290600101906020018083116119ff57829003601f168201915b505050505081526020019060010190611984565b505050915250909392505050565b6000818152601060205260408120546011548110611a9e5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b505060009081526010602052604090205490565b6000818152600c60205260408120546001600160a01b031680611b265760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610be0565b92915050565b6000546001600160a01b03163314611b865760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b600091825260086020526040909120805463ffffffff191663ffffffff909216919091179055565b6000818152600c6020526040812054819081906001600160a01b031680611c265760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610be0565b5050506000918252506007602052604090206001810154815460029092015490926001600160a01b0390921691565b3360009081526012602052604090205460ff16611cc95760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b816011548110611d1b5760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000838152600e60209081526040822080546001810182559083529120016111558382613a05565b60006001600160a01b038216611dc15760405162461bcd60e51b815260206004820152602760248201527f4e46543a2062616c616e636520717565727920666f7220746865207a65726f2060448201527f61646472657373000000000000000000000000000000000000000000000000006064820152608401610be0565b506001600160a01b03166000908152600d602052604090205490565b8282826002805403611e315760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610be0565b60028055600080611e4188611bae565b5091509150813411611eba5760405162461bcd60e51b8152602060048201526024808201527f4e657720626964206d7573742065786365656420746865206578697374696e6760448201527f206f6e65000000000000000000000000000000000000000000000000000000006064820152608401610be0565b60008215611eeb576040516000906001600160a01b0384169085156108fc0290869084818181858888f15050505050505b34611ef58a61259f565b108015611f0a57506000611f088a61259f565b115b15611f1f57611f188961259f565b9050611f22565b50345b600089815260076020526040908190206001810183905580546001600160a01b03191633178155426002909101555181908a907f223d0d5db4846341da7a5cc902b1a7c597e63b6c73b1c6267dc931d290c7affb90611f84908c908c90613bda565b60405180910390a334611f968a61259f565b108015611fab57506000611fa98a61259f565b115b15611fe2576000336108fc611fbf8c61259f565b611fc99034613b9e565b6040518115909202916000818181858888f15050505050505b5050600160025550600080611ff685611bae565b509150915060006120068661259f565b11801561201b5750816120188661259f565b11155b1561210857600061202c8387612d24565b6120369084613b9e565b905061204186611ab2565b6001600160a01b0316826001600160a01b0316877fc9b9afd9684b23c6b22a41016c08e8954ac118220c0a52f00b8774c46580e9a38460405161208691815260200190565b60405180910390a4600061209987611ab2565b6001600160a01b03166108fc839081150290604051600060405180830381858888f160008c815260076020908152604080832080546001600160a01b03191681556001810184905560020183905560069091528120559450612105935061146c92508a9150611ab29050565b50505b5050505050505050565b6000546001600160a01b0316331461216c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b6000918252600f6020526040909120805463ffffffff191663ffffffff909216919091179055565b6000828152600360205260409020805460609190839081106121b8576121b8613944565b9060005260206000200180546121cd9061395a565b80601f01602080910402602001604051908101604052809291908181526020018280546121f99061395a565b80156122465780601f1061221b57610100808354040283529160200191612246565b820191906000526020600020905b81548152906001019060200180831161222957829003601f168201915b5050505050905092915050565b3360009081526012602052604090205460ff166122c75760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b8060115481106123195760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000828152600e602090815260408083208054600181018255908452828420825193840190925292825290910190610f109082613a05565b6000546001600160a01b031633146123ab5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b63ffffffff909216600090815260046020526040902080546001600160a01b039092166001600160a01b031990921691909117815560010155565b6060600b8054610b0e9061395a565b6000828152601060205260409020546011546060919081106124595760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000848152601060209081526040808320548352600e90915290208054849081106118ad576118ad613944565b6000546001600160a01b0316156124df5760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610be0565b600080546001600160a01b0319163390811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a362015180600555600a6125318482613a05565b50600b61253e8382613a05565b506000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec80546001600160a01b031916331790557f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed555050565b6000818152600c60205260408120546001600160a01b0316806126135760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610be0565b505060009081526006602052604090205490565b6000546001600160a01b031633146126815760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b611155848484846131b9565b600061269c3386868686612dab565b7f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad97683836040516126cd929190613bda565b60405180910390a1506001949350505050565b3360009081526012602052604090205460ff166127545760405162461bcd60e51b815260206004820152602c60248201527f436c61737369666965644e46543a2063616c6c6572206973206e6f742074686560448201526b1021b630b9b99020b236b4b760a11b6064820152608401610be0565b60005b82811015610f10576000828152600e6020908152604080832080546001810182559084528284208251938401909252928252909101906127979082613a05565b50806127a281613ac5565b915050612757565b6000336127b683611ab2565b6001600160a01b03161461281b5760405162461bcd60e51b815260206004820152602660248201527f4e46543a207472616e73666572206f6620746f6b656e2074686174206973206e60448201526537ba1037bbb760d11b6064820152608401610be0565b6001600160a01b03831661287b5760405162461bcd60e51b815260206004820152602160248201527f4e46543a207472616e7366657220746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610be0565b600082815260066020526040812055336000908152600d602052604081208054600192906128aa908490613b9e565b90915550506001600160a01b0383166000908152600d602052604081208054600192906128d89084906139a4565b90915550506000828152600c602052604080822080546001600160a01b0319166001600160a01b0387169081179091559051849233917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9190a450600192915050565b6000546001600160a01b031633146129955760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b6001600160a01b03919091166000908152600160205260409020805460ff1916911515919091179055565b6000546001600160a01b03163314612a1a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b6001600160a01b03919091166000908152601260205260409020805460ff1916911515919091179055565b6060816011548110612a995760405162461bcd60e51b815260206004820152601c60248201527f5175657269656420636c61737320646f6573206e6f74206578697374000000006044820152606401610be0565b6000838152600e6020908152604080832080548251818502810185019093528083529193909284015b8282101561182c578382906000526020600020018054612ae19061395a565b80601f0160208091040260200160405190810160405280929190818152602001828054612b0d9061395a565b8015612b5a5780601f10612b2f57610100808354040283529160200191612b5a565b820191906000526020600020905b815481529060010190602001808311612b3d57829003601f168201915b505050505081526020019060010190612ac2565b6000546001600160a01b03163314612bc85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610be0565b6001600160a01b038116612c445760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610be0565b612c4d816131f4565b50565b600083815260036020908152604082208054600181018255908352912001611155828483613ade565b612cd282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525089815260036020526040902080549093508892508210905061162857611628613944565b60008581526003602052604090208054859081106110d2576110d2613944565b6000612d0033600954613244565b50600980549081906000612d1383613ac5565b9190505550612d2181613252565b90565b60008181526008602090815260408083205463ffffffff168084526004909252822080546001909101546001600160a01b039091169083620186a0612d698389613bee565b612d739190613c05565b90506000836001600160a01b03166108fc839081150290604051600060405180830381858888f150949b9a5050505050505050505050565b846001600160a01b0316612dbe84611ab2565b6001600160a01b031614612e235760405162461bcd60e51b815260206004820152602660248201527f4e46543a207472616e73666572206f6620746f6b656e2074686174206973206e60448201526537ba1037bbb760d11b6064820152608401610be0565b6001600160a01b038416612e835760405162461bcd60e51b815260206004820152602160248201527f4e46543a207472616e7366657220746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610be0565b6000838152600660205260408120556001600160a01b0385166000908152600d60205260408120805460019290612ebb908490613b9e565b90915550506001600160a01b0384166000908152600d60205260408120805460019290612ee99084906139a4565b90915550506000838152600c6020526040902080546001600160a01b0319166001600160a01b0386169081179091553b15612fb0576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063150b7a0290612f6b9033908990889088908890600401613c27565b6020604051808303816000875af1158015612f8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fae9190613c65565b505b82846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050565b80516060908390839061300d5761300d613ca7565b60008151835161301d91906139a4565b67ffffffffffffffff81111561303557613035613495565b6040519080825280601f01601f19166020018201604052801561305f576020820181803683370190505b509050806000805b85518210156131075785828151811061308257613082613944565b01602001517fff000000000000000000000000000000000000000000000000000000000000001683826130b481613ac5565b9350815181106130c6576130c6613944565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350816130ff81613ac5565b925050613067565b600091505b84518210156131ac5784828151811061312757613127613944565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016838261315981613ac5565b93508151811061316b5761316b613944565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350816131a481613ac5565b92505061310c565b5090979650505050505050565b6000848152600360205260409020805483918391869081106131dd576131dd613944565b9060005260206000200191826110e8929190613ade565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61324e828261329f565b5050565b6000818152600360205260408120549003612c4d576000818152600360209081526040808320805460018101825590845282842082519384019092529282529091019061324e9082613a05565b6001600160a01b0382166132f55760405162461bcd60e51b815260206004820152601d60248201527f4e46543a206d696e7420746f20746865207a65726f20616464726573730000006044820152606401610be0565b6000818152600c60205260409020546001600160a01b03161561335a5760405162461bcd60e51b815260206004820152601960248201527f4e46543a20746f6b656e20616c7265616479206d696e746564000000000000006044820152606401610be0565b6001600160a01b0382166000908152600d602052604081208054600192906133839084906139a4565b90915550506000818152600c602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000602082840312156133f357600080fd5b5035919050565b6000815180845260005b8181101561342057602081850181015186830182015201613404565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061345360208301846133fa565b9392505050565b6000806040838503121561346d57600080fd5b50508035926020909101359150565b803563ffffffff8116811461349057600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126134bc57600080fd5b813567ffffffffffffffff808211156134d7576134d7613495565b604051601f8301601f19908116603f011681019082821181831017156134ff576134ff613495565b8160405283815286602085880101111561351857600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561354b57600080fd5b6135548361347c565b9150602083013567ffffffffffffffff81111561357057600080fd5b61357c858286016134ab565b9150509250929050565b60008083601f84011261359857600080fd5b50813567ffffffffffffffff8111156135b057600080fd5b6020830191508360208285010111156135c857600080fd5b9250929050565b6000806000604084860312156135e457600080fd5b83359250602084013567ffffffffffffffff81111561360257600080fd5b61360e86828701613586565b9497909650939450505050565b60008060006060848603121561363057600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561365557600080fd5b613661868287016134ab565b9150509250925092565b6000806000806060858703121561368157600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156136a657600080fd5b6136b287828801613586565b95989497509550505050565b600081518084526020808501808196508360051b8101915082860160005b858110156137065782840389526136f48483516133fa565b988501989350908401906001016136dc565b5091979650505050505050565b60208152600061345360208301846136be565b602081526000825160208084015261374160408401826136be565b949350505050565b80356001600160a01b038116811461349057600080fd5b60006020828403121561377257600080fd5b61345382613749565b6000806040838503121561378e57600080fd5b8235915061379e6020840161347c565b90509250929050565b600080604083850312156137ba57600080fd5b82359150602083013567ffffffffffffffff81111561357057600080fd5b6000602082840312156137ea57600080fd5b6134538261347c565b60008060006060848603121561380857600080fd5b6138118461347c565b925061381f60208501613749565b9150604084013590509250925092565b60008060006060848603121561384457600080fd5b833567ffffffffffffffff8082111561385c57600080fd5b613868878388016134ab565b9450602086013591508082111561387e57600080fd5b5061388b868287016134ab565b925050604084013590509250925092565b600080600080606085870312156138b257600080fd5b6138bb85613749565b935060208501359250604085013567ffffffffffffffff8111156136a657600080fd5b600080604083850312156138f157600080fd5b6138fa83613749565b946020939093013593505050565b6000806040838503121561391b57600080fd5b61392483613749565b91506020830135801515811461393957600080fd5b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061396e57607f821691505b60208210810361183357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115611b2657611b2661398e565b601f821115610f1057600081815260208120601f850160051c810160208610156139de5750805b601f850160051c820191505b818110156139fd578281556001016139ea565b505050505050565b815167ffffffffffffffff811115613a1f57613a1f613495565b613a3381613a2d845461395a565b846139b7565b602080601f831160018114613a685760008415613a505750858301515b600019600386901b1c1916600185901b1785556139fd565b600085815260208120601f198616915b82811015613a9757888601518255948401946001909101908401613a78565b5085821015613ab55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060018201613ad757613ad761398e565b5060010190565b67ffffffffffffffff831115613af657613af6613495565b613b0a83613b04835461395a565b836139b7565b6000601f841160018114613b3e5760008515613b265750838201355b600019600387901b1c1916600186901b1783556110e8565b600083815260209020601f19861690835b82811015613b6f5786850135825560209485019460019092019101613b4f565b5086821015613b8c5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81810381811115611b2657611b2661398e565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b602081526000613741602083018486613bb1565b8082028115828204841417611b2657611b2661398e565b600082613c2257634e487b7160e01b600052601260045260246000fd5b500490565b60006001600160a01b03808816835280871660208401525084604083015260806060830152613c5a608083018486613bb1565b979650505050505050565b600060208284031215613c7757600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461345357600080fd5b634e487b7160e01b600052600160045260246000fdfea2646970667358221220b4439bf81c4d951e3cb2b6c85d9d2ca693125f0a4c08b56a6fbdbb5a58ac074a64736f6c63430008110033