Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- MuchaNFT
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 1000
- EVM Version
- default
- Verified at
- 2024-09-26T15:33:13.929946Z
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 Initializes the contract setting the deployer as the initial owner.
constructor() {
_transferOwnership(_msgSender());
}
*/
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
/*
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
*/
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
abstract contract MinterRole is Ownable {
event SetMinterRole(address minter, bool status);
mapping (address => bool) public minter_role;
function setMinterRole(address _who, bool _status) public onlyOwner
{
minter_role[_who] = _status;
emit SetMinterRole(_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 data);
event NewPrice (uint256 indexed tokenID, uint256 indexed priceValue, bytes data);
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
abstract contract ExtendedNFT is ICallistoNFT, ReentrancyGuard {
using Strings for string;
using Address for address;
event TokenPropertyUpdated(uint tokenID, uint propertyID);
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 memory _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 pure 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 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 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 override returns (Properties memory)
{
return _tokenProperties[_tokenId];
}
function getTokenProperty(uint256 _tokenId, uint256 _propertyId) public view returns (string memory)
{
return _tokenProperties[_tokenId].properties[_propertyId];
}
function getUserContent(uint256 _tokenId) public view override returns (string memory _content)
{
return (_tokenProperties[_tokenId].properties[0]);
}
function setUserContent(uint256 _tokenId, string calldata _content) public override returns (bool success)
{
require(msg.sender == ownerOf(_tokenId), "NFT: only owner can change NFT content");
_tokenProperties[_tokenId].properties[0] = _content;
emit TokenPropertyUpdated(_tokenId, 0) ;
return true;
}
function _addPropertyWithContent(uint256 _tokenId, string calldata _content) internal
{
// Check permission criteria
_tokenProperties[_tokenId].properties.push(_content);
uint newPropertyID = _tokenProperties[_tokenId].properties.length - 1;
emit TokenPropertyUpdated(_tokenId, newPropertyID);
}
function _modifyProperty(uint256 _tokenId, uint256 _propertyId, string calldata _content) internal
{
_tokenProperties[_tokenId].properties[_propertyId] = _content;
emit TokenPropertyUpdated(_tokenId, _propertyId);
}
function _appendProperty(uint256 _tokenId, uint256 _propertyId, string calldata _content) internal
{
_tokenProperties[_tokenId].properties[_propertyId] = _tokenProperties[_tokenId].properties[_propertyId].concat(_content);
emit TokenPropertyUpdated(_tokenId, _propertyId);
}
function balanceOf(address owner) public view override returns (uint256) {
require(owner != address(0), "NFT: balance query for the zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view 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 override nonReentrant {
require(ownerOf(_tokenId) == msg.sender, "Setting asks is only allowed for owned NFTs!");
_asks[_tokenId] = _amountInWEI;
emit NewPrice(_tokenId, _amountInWEI, _data);
}
function setBid(uint256 _tokenId, bytes calldata _data) payable checkTrade(_tokenId, _data) public override nonReentrant
{
(uint256 _previousBid, address payable _previousBidder, ) = bidOf(_tokenId);
require(msg.value > _previousBid, "New bid must exceed the existing one");
uint256 _bid;
bool sent;
// Return previous bid if the current one exceeds it.
if(_previousBid != 0)
{
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)
{
sent = payable(msg.sender).send(msg.value - priceOf(_tokenId));
}
}
function withdrawBid(uint256 _tokenId) public 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];
emit NewBid(_tokenId, 0, "0x7769746864726177426964");
return true;
}
function name() public view override returns (string memory) {
return _name;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function transfer(address _to, uint256 _tokenId, bytes memory _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 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 {
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 {
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 memory data
) internal {
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;
event ClassPropertyUpdated(uint classID, uint propertyID);
event TokenClassChanged(uint _tokenID, uint _tokenClass);
mapping (uint256 => string[]) public class_properties;
mapping (uint256 => uint32) public class_feeLevel;
mapping (uint256 => uint256) public token_classes;
uint256 public nextClassIndex = 0;
modifier onlyExistingClasses(uint256 classId)
{
require(classId < nextClassIndex, "Queried class does not exist");
_;
}
function setClassForTokenID(uint256 _tokenID, uint256 _tokenClass) public onlyOwner override
{
token_classes[_tokenID] = _tokenClass;
emit TokenClassChanged(_tokenID, _tokenClass);
}
function addNewTokenClass(uint32 _feeLevel, string memory _property) public onlyOwner 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.
emit ClassPropertyUpdated(nextClassIndex, 0);
nextClassIndex++;
}
function addTokenClassProperties(uint256 _propertiesCount, uint256 classId) public onlyOwner override
{
for (uint i = 0; i < _propertiesCount; i++)
{
class_properties[classId].push("");
}
}
function modifyClassProperty(uint256 _classID, uint256 _propertyID, string memory _content) public onlyOwner onlyExistingClasses(_classID) override
{
class_properties[_classID][_propertyID] = _content;
emit ClassPropertyUpdated(_classID, _propertyID);
}
function getClassProperty(uint256 _classID, uint256 _propertyID) public view onlyExistingClasses(_classID) override returns (string memory)
{
return class_properties[_classID][_propertyID];
}
function addClassProperty(uint256 _classID) public onlyOwner onlyExistingClasses(_classID) override
{
class_properties[_classID].push("");
}
function addClassPropertyWithContent(uint256 _classID, string memory _content) public onlyOwner onlyExistingClasses(_classID)
{
class_properties[_classID].push(_content);
uint newPropertyID = class_properties[_classID].length - 1;
emit ClassPropertyUpdated(_classID, newPropertyID);
}
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 onlyOwner onlyExistingClasses(_classID) override
{
class_properties[_classID][_propertyID] = class_properties[_classID][_propertyID].concat(_content);
emit ClassPropertyUpdated(_classID, _propertyID);
}
}
contract MuchaNFT 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;
}
/* onlyOwner or Minter */
function addPropertyWithContent(uint256 _tokenId, string calldata _content) public
{
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);
}
function tokenURI(uint256 _tokenID) public view onlyExistingClasses(token_classes[_tokenID]) returns (string memory)
{
//Consider that the first (0) property has the same info that a JSON
return class_properties[token_classes[_tokenID]][0];
}
}
Contract ABI
[{"type":"event","name":"ClassPropertyUpdated","inputs":[{"type":"uint256","name":"classID","internalType":"uint256","indexed":false},{"type":"uint256","name":"propertyID","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NewBid","inputs":[{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"uint256","name":"bidAmount","internalType":"uint256","indexed":true},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"NewPrice","inputs":[{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"uint256","name":"priceValue","internalType":"uint256","indexed":true},{"type":"bytes","name":"data","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":"SetMinterRole","inputs":[{"type":"address","name":"minter","internalType":"address","indexed":false},{"type":"bool","name":"status","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"TokenClassChanged","inputs":[{"type":"uint256","name":"_tokenID","internalType":"uint256","indexed":false},{"type":"uint256","name":"_tokenClass","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TokenPropertyUpdated","inputs":[{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":false},{"type":"uint256","name":"propertyID","internalType":"uint256","indexed":false}],"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":"_content","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":"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":"pure","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":"string","name":"","internalType":"string"}],"name":"tokenURI","inputs":[{"type":"uint256","name":"_tokenID","internalType":"uint256"}]},{"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
0x608060405262015180600555600060115534801561001c57600080fd5b506001600255613e68806100316000396000f3fe6080604052600436106103135760003560e01c806370a082311161019a578063b9186d7d116100e1578063c98e0c3c1161008a578063e29fb03611610064578063e29fb036146109b4578063e6470059146109ca578063f2fde38b146109ea57600080fd5b8063c98e0c3c1461092c578063cb177b1e1461094c578063d75d1e661461096c57600080fd5b8063be671058116100bb578063be671058146108bf578063c1940f1b146108df578063c87b56dd1461090c57600080fd5b8063b9186d7d1461085f578063bb0537171461087f578063be45fd621461089f57600080fd5b80638da5cb5b1161014357806395d89b411161011d57806395d89b411461080a5780639de4792e1461081f578063b119490e1461083f57600080fd5b80638da5cb5b146107b65780638e39e18c146107d457806391100695146107f457600080fd5b806378317f3f1161017457806378317f3f146107565780637ab56e521461077657806380483a6a1461079657600080fd5b806370a08231146106c457806373baa651146106e457806374c29ce3146106f757600080fd5b80633e0bb7831161025e578063543dc7fa11610207578063648fbe40116101e1578063648fbe4014610641578063649ccc141461066157806369a13712146106a457600080fd5b8063543dc7fa146105a35780635a3b7e42146105c35780636352211e1461060957600080fd5b80634c1720a4116102385780634c1720a4146105265780634edea11114610546578063510910bb1461057357600080fd5b80633e0bb783146104b95780634774d93f146104d95780634bb2ddd4146104f957600080fd5b8063290e008c116102c05780633add5fa11161029a5780633add5fa1146104595780633c65b3eb146104795780633d8073f11461049957600080fd5b8063290e008c146103f95780632a6d3f44146104195780633054d9cb1461043957600080fd5b80631d734c8f116102f15780631d734c8f146103935780631f38e654146103b757806325498c75146103d957600080fd5b806302ff368a1461031857806306fdde031461034e5780630eaaf4c814610363575b600080fd5b34801561032457600080fd5b506103386103333660046134fd565b610a0a565b604051610345919061355c565b60405180910390f35b34801561035a57600080fd5b50610338610ac4565b34801561036f57600080fd5b5061038361037e3660046134fd565b610b56565b6040519015158152602001610345565b34801561039f57600080fd5b506103a960115481565b604051908152602001610345565b3480156103c357600080fd5b506103d76103d2366004613576565b610d6d565b005b3480156103e557600080fd5b506103d76103f436600461365d565b610e05565b34801561040557600080fd5b506103d76104143660046136f4565b610efa565b34801561042557600080fd5b506103836104343660046136f4565b610f7b565b34801561044557600080fd5b506103d7610454366004613740565b611089565b34801561046557600080fd5b506103d7610474366004613790565b61118b565b34801561048557600080fd5b506103a96104943660046134fd565b6111e5565b3480156104a557600080fd5b506103d76104b4366004613790565b6112d7565b3480156104c557600080fd5b506103386104d4366004613576565b611571565b3480156104e557600080fd5b506103d76104f4366004613740565b61162a565b34801561050557600080fd5b506105196105143660046134fd565b611799565b6040516103459190613838565b34801561053257600080fd5b50610338610541366004613576565b6118d7565b34801561055257600080fd5b506105666105613660046134fd565b6119d5565b604051610345919061384b565b34801561057f57600080fd5b5061038361058e366004613885565b60016020526000908152604090205460ff1681565b3480156105af57600080fd5b506103a96105be3660046134fd565b611aca565b3480156105cf57600080fd5b5060408051808201909152600b81527f43616c6c6973746f4e46540000000000000000000000000000000000000000006020820152610338565b34801561061557600080fd5b506106296106243660046134fd565b611b2c565b6040516001600160a01b039091168152602001610345565b34801561064d57600080fd5b506103d761065c3660046138a0565b611ba6565b34801561066d57600080fd5b5061068161067c3660046134fd565b611c16565b604080519384526001600160a01b03909216602084015290820152606001610345565b3480156106b057600080fd5b506103d76106bf3660046138cc565b611cbd565b3480156106d057600080fd5b506103a96106df366004613885565b611dc2565b6103d76106f23660046136f4565b611e5c565b34801561070357600080fd5b506107376107123660046138fd565b600460205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b039093168352602083019190915201610345565b34801561076257600080fd5b506103d76107713660046138a0565b6121c8565b34801561078257600080fd5b50610338610791366004613576565b612238565b3480156107a257600080fd5b506103d76107b13660046134fd565b6122f7565b3480156107c257600080fd5b506000546001600160a01b0316610629565b3480156107e057600080fd5b506103d76107ef366004613918565b6123b7565b34801561080057600080fd5b506103a960055481565b34801561081657600080fd5b5061033861243a565b34801561082b57600080fd5b5061033861083a366004613576565b612449565b34801561084b57600080fd5b506103d761085a366004613954565b6124c8565b34801561086b57600080fd5b506103a961087a3660046134fd565b6125e1565b34801561088b57600080fd5b506103d761089a366004613790565b612669565b3480156108ab57600080fd5b506103836108ba3660046139c1565b6126bd565b3480156108cb57600080fd5b506103d76108da366004613576565b6126fa565b3480156108eb57600080fd5b506103a96108fa3660046134fd565b60106020526000908152604090205481565b34801561091857600080fd5b506103386109273660046134fd565b612798565b34801561093857600080fd5b50610383610947366004613a22565b6128b1565b34801561095857600080fd5b506103d7610967366004613a4c565b612a42565b34801561097857600080fd5b5061099f6109873660046134fd565b600f6020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610345565b3480156109c057600080fd5b506103a960095481565b3480156109d657600080fd5b506105196109e53660046134fd565b612ae6565b3480156109f657600080fd5b506103d7610a05366004613885565b612bfd565b6000818152600360205260408120805460609290610a2a57610a2a613a88565b906000526020600020018054610a3f90613a9e565b80601f0160208091040260200160405190810160405280929190818152602001828054610a6b90613a9e565b8015610ab85780601f10610a8d57610100808354040283529160200191610ab8565b820191906000526020600020905b815481529060010190602001808311610a9b57829003601f168201915b50505050509050919050565b6060600a8054610ad390613a9e565b80601f0160208091040260200160405190810160405280929190818152602001828054610aff90613a9e565b8015610b4c5780601f10610b2157610100808354040283529160200191610b4c565b820191906000526020600020905b815481529060010190602001808311610b2f57829003601f168201915b5050505050905090565b60006002805403610bae5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002805560008080610bbf85611c16565b91945092509050336001600160a01b03831614610c445760405162461bcd60e51b815260206004820152602260248201527f43616e206e6f7420776974686472617720736f6d656f6e6520656c736573206260448201527f69640000000000000000000000000000000000000000000000000000000000006064820152608401610ba5565b600554610c519082613ae8565b4211610c9f5760405162461bcd60e51b815260206004820152601260248201527f4269642069732074696d652d6c6f636b656400000000000000000000000000006044820152606401610ba5565b6040516000906001600160a01b0384169085156108fc0290869084818181858888f160008b81526007602052604080822080546001600160a01b0319168155600181018390556002018290555191965094508a93507f223d0d5db4846341da7a5cc902b1a7c597e63b6c73b1c6267dc931d290c7affb9250610d53915060208082526018908201527f3078373736393734363836343732363137373432363936340000000000000000604082015260600190565b60405180910390a360019450505050506001600255919050565b6000546001600160a01b03163314610db55760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b60008281526010602090815260409182902083905581518481529081018390527fa8b2c0f94a578b5a88c9c7d9242237165ea684a64cd32968c7f0dd6edd22dbe091015b60405180910390a15050565b6000546001600160a01b03163314610e4d5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6011546000908152600e6020908152604082208054600181018255908352912001610e788282613b49565b50601180546000908152600f6020526040808220805463ffffffff871663ffffffff19909116179055915491517f949a1ec513916b5e46ab2c5681369a4651bba074831b8da896b06a94e8d041b692610ed992908252602082015260400190565b60405180910390a160118054906000610ef183613c09565b91905055505050565b33610f0d6000546001600160a01b031690565b6001600160a01b03161480610f3157503360009081526001602052604090205460ff165b610f6b5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b610f76838383612ccd565b505050565b6000610f8684611b2c565b6001600160a01b0316336001600160a01b03161461100c5760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f6e6c79206f776e65722063616e206368616e6765204e4654206360448201527f6f6e74656e7400000000000000000000000000000000000000000000000000006064820152608401610ba5565b60008481526003602052604081208054859285929161102d5761102d613a88565b906000526020600020019182611044929190613c22565b5060408051858152600060208201527f0fe79316286f6a1e5cf32c3c4ff10c2a66b9cd66da3353db3789c4042ffb44ee91015b60405180910390a15060019392505050565b6000546001600160a01b031633146110d15760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b8260115481106111115760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000848152600e6020526040902080548391908590811061113457611134613a88565b90600052602060002001908161114a9190613b49565b5060408051858152602081018590527f949a1ec513916b5e46ab2c5681369a4651bba074831b8da896b06a94e8d041b691015b60405180910390a150505050565b6000546001600160a01b031633146111d35760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6111df84848484612d4b565b50505050565b60008160115481106112275760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b3360009081526001602052604090205460ff166112865760405162461bcd60e51b815260206004820152601460248201527f4d696e74657220726f6c652072657175697265640000000000000000000000006044820152606401610ba5565b61128e612e11565b6000818152601060209081526040808320879055958252600f8152858220548383526008909152949020805463ffffffff191663ffffffff909516949094179093555090919050565b8382828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060025460011901915061136390505760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ba5565b600280553361137187611b2c565b6001600160a01b0316146113ed5760405162461bcd60e51b815260206004820152602c60248201527f53657474696e672061736b73206973206f6e6c7920616c6c6f77656420666f7260448201527f206f776e6564204e4654732100000000000000000000000000000000000000006064820152608401610ba5565b6000868152600660205260409081902086905551859087907f403cbda48c4d379b57469bea093b63817816d893b467842ee46fd1c3c29c05f8906114349088908890613ce3565b60405180910390a3600160025560008061144d84611c16565b5091509150600061145d856125e1565b11801561147257508161146f856125e1565b11155b156115675760006114838386612e43565b61148d9084613d12565b905061149885611b2c565b6001600160a01b0316826001600160a01b0316867fc9b9afd9684b23c6b22a41016c08e8954ac118220c0a52f00b8774c46580e9a3846040516114dd91815260200190565b60405180910390a460006114f086611b2c565b6001600160a01b03166108fc839081150290604051600060405180830381858888f160008b815260076020908152604080832080546001600160a01b03191681556001810184905560020183905560069091528120559450611564935061155c9250899150611b2c9050565b848888612eca565b50505b5050505050505050565b600e602052816000526040600020818154811061158d57600080fd5b906000526020600020016000915091505080546115a990613a9e565b80601f01602080910402602001604051908101604052809291908181526020018280546115d590613a9e565b80156116225780601f106115f757610100808354040283529160200191611622565b820191906000526020600020905b81548152906001019060200180831161160557829003601f168201915b505050505081565b6000546001600160a01b031633146116725760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b8260115481106116b25760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000848152600e602052604090208054611779918491869081106116d8576116d8613a88565b9060005260206000200180546116ed90613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461171990613a9e565b80156117665780601f1061173b57610100808354040283529160200191611766565b820191906000526020600020905b81548152906001019060200180831161174957829003601f168201915b505050505061311490919063ffffffff16565b6000858152600e6020526040902080548590811061113457611134613a88565b6000818152601060205260409020546011546060919081106117eb5760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000838152601060209081526040808320548352600e825280832080548251818502810185019093528083529193909284015b828210156118ca57838290600052602060002001805461183d90613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461186990613a9e565b80156118b65780601f1061188b576101008083540402835291602001916118b6565b820191906000526020600020905b81548152906001019060200180831161189957829003601f168201915b50505050508152602001906001019061181e565b5050505091505b50919050565b60608260115481106119195760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000848152600e6020526040902080548490811061193957611939613a88565b90600052602060002001805461194e90613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461197a90613a9e565b80156119c75780601f1061199c576101008083540402835291602001916119c7565b820191906000526020600020905b8154815290600101906020018083116119aa57829003601f168201915b505050505091505092915050565b604080516020808201835260608252600084815260038252838120845181548085028201870187529381018481529495909491938593859285015b82821015611abc578382906000526020600020018054611a2f90613a9e565b80601f0160208091040260200160405190810160405280929190818152602001828054611a5b90613a9e565b8015611aa85780601f10611a7d57610100808354040283529160200191611aa8565b820191906000526020600020905b815481529060010190602001808311611a8b57829003601f168201915b505050505081526020019060010190611a10565b505050915250909392505050565b6000818152601060205260408120546011548110611b185760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b505060009081526010602052604090205490565b6000818152600c60205260408120546001600160a01b031680611ba05760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610ba5565b92915050565b6000546001600160a01b03163314611bee5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b600091825260086020526040909120805463ffffffff191663ffffffff909216919091179055565b6000818152600c6020526040812054819081906001600160a01b031680611c8e5760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610ba5565b5050506000918252506007602052604090206001810154815460029092015490926001600160a01b0390921691565b6000546001600160a01b03163314611d055760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b816011548110611d455760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000838152600e6020908152604082208054600181018255908352912001611d6d8382613b49565b506000838152600e6020526040812054611d8990600190613d12565b60408051868152602081018390529192507f949a1ec513916b5e46ab2c5681369a4651bba074831b8da896b06a94e8d041b6910161117d565b60006001600160a01b038216611e405760405162461bcd60e51b815260206004820152602760248201527f4e46543a2062616c616e636520717565727920666f7220746865207a65726f2060448201527f61646472657373000000000000000000000000000000000000000000000000006064820152608401610ba5565b506001600160a01b03166000908152600d602052604090205490565b8282828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050600254600119019150611ee890505760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ba5565b60028055600080611ef887611c16565b5091509150813411611f715760405162461bcd60e51b8152602060048201526024808201527f4e657720626964206d7573742065786365656420746865206578697374696e6760448201527f206f6e65000000000000000000000000000000000000000000000000000000006064820152608401610ba5565b6000808315611fa1576040516001600160a01b0384169085156108fc029086906000818181858888f19450505050505b34611fab8a6125e1565b108015611fc057506000611fbe8a6125e1565b115b15611fd557611fce896125e1565b9150611fd9565b3491505b600089815260076020526040908190206001810184905580546001600160a01b03191633178155426002909101555182908a907f223d0d5db4846341da7a5cc902b1a7c597e63b6c73b1c6267dc931d290c7affb9061203b908c908c90613ce3565b60405180910390a33461204d8a6125e1565b108015612062575060006120608a6125e1565b115b1561209757336108fc6120748b6125e1565b61207e9034613d12565b6040518115909202916000818181858888f19450505050505b505060016002555060009050806120ad84611c16565b509150915060006120bd856125e1565b1180156120d25750816120cf856125e1565b11155b156121bf5760006120e38386612e43565b6120ed9084613d12565b90506120f885611b2c565b6001600160a01b0316826001600160a01b0316867fc9b9afd9684b23c6b22a41016c08e8954ac118220c0a52f00b8774c46580e9a38460405161213d91815260200190565b60405180910390a4600061215086611b2c565b6001600160a01b03166108fc839081150290604051600060405180830381858888f160008b815260076020908152604080832080546001600160a01b031916815560018101849055600201839055600690915281205594506121bc935061155c9250899150611b2c9050565b50505b50505050505050565b6000546001600160a01b031633146122105760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6000918252600f6020526040909120805463ffffffff191663ffffffff909216919091179055565b60008281526003602052604090208054606091908390811061225c5761225c613a88565b90600052602060002001805461227190613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461229d90613a9e565b80156122ea5780601f106122bf576101008083540402835291602001916122ea565b820191906000526020600020905b8154815290600101906020018083116122cd57829003601f168201915b5050505050905092915050565b6000546001600160a01b0316331461233f5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b80601154811061237f5760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000828152600e602090815260408083208054600181018255908452828420825193840190925292825290910190610f769082613b49565b6000546001600160a01b031633146123ff5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b63ffffffff909216600090815260046020526040902080546001600160a01b039092166001600160a01b031990921691909117815560010155565b6060600b8054610ad390613a9e565b60008281526010602052604090205460115460609190811061249b5760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000848152601060209081526040808320548352600e909152902080548490811061193957611939613a88565b6000546001600160a01b0316156125215760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610ba5565b600080546001600160a01b0319163390811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a362015180600555600a6125738482613b49565b50600b6125808382613b49565b506000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec80546001600160a01b031916331790557f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed555050565b6000818152600c60205260408120546001600160a01b0316806126555760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610ba5565b505060009081526006602052604090205490565b6000546001600160a01b031633146126b15760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6111df848484846132d5565b60006126cb33858585612eca565b7f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad97682604051611077919061355c565b6000546001600160a01b031633146127425760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b60005b82811015610f76576000828152600e6020908152604080832080546001810182559084528284208251938401909252928252909101906127859082613b49565b508061279081613c09565b915050612745565b6000818152601060205260409020546011546060919081106127ea5760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000838152601060209081526040808320548352600e9091528120805490919061281657612816613a88565b90600052602060002001805461282b90613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461285790613a9e565b80156128a45780601f10612879576101008083540402835291602001916128a4565b820191906000526020600020905b81548152906001019060200180831161288757829003601f168201915b5050505050915050919050565b6000336128bd83611b2c565b6001600160a01b0316146129225760405162461bcd60e51b815260206004820152602660248201527f4e46543a207472616e73666572206f6620746f6b656e2074686174206973206e60448201526537ba1037bbb760d11b6064820152608401610ba5565b6001600160a01b0383166129825760405162461bcd60e51b815260206004820152602160248201527f4e46543a207472616e7366657220746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610ba5565b600082815260066020526040812055336000908152600d602052604081208054600192906129b1908490613d12565b90915550506001600160a01b0383166000908152600d602052604081208054600192906129df908490613ae8565b90915550506000828152600c602052604080822080546001600160a01b0319166001600160a01b0387169081179091559051849233917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9190a450600192915050565b6000546001600160a01b03163314612a8a5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f6b0f890a293c8f56a7635ad061c90250965b8af8e8bdbeb56d434b97281a74629101610df9565b6060816011548110612b285760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000838152600e6020908152604080832080548251818502810185019093528083529193909284015b828210156118ca578382906000526020600020018054612b7090613a9e565b80601f0160208091040260200160405190810160405280929190818152602001828054612b9c90613a9e565b8015612be95780601f10612bbe57610100808354040283529160200191612be9565b820191906000526020600020905b815481529060010190602001808311612bcc57829003601f168201915b505050505081526020019060010190612b51565b6000546001600160a01b03163314612c455760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6001600160a01b038116612cc15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ba5565b612cca81613310565b50565b600083815260036020908152604082208054600181018255908352912001612cf6828483613c22565b50600083815260036020526040812054612d1290600190613d12565b60408051868152602081018390529192507f0fe79316286f6a1e5cf32c3c4ff10c2a66b9cd66da3353db3789c4042ffb44ee910161117d565b612da482828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052508981526003602052604090208054909350889250821090506116d8576116d8613a88565b6000858152600360205260409020805485908110612dc457612dc4613a88565b906000526020600020019081612dda9190613b49565b5060408051858152602081018590527f0fe79316286f6a1e5cf32c3c4ff10c2a66b9cd66da3353db3789c4042ffb44ee910161117d565b6000612e1f33600954613360565b50600980549081906000612e3283613c09565b9190505550612e408161336e565b90565b60008181526008602090815260408083205463ffffffff168084526004909252822080546001909101546001600160a01b039091169083620186a0612e888389613d25565b612e929190613d3c565b90506000836001600160a01b03166108fc839081150290604051600060405180830381858888f150949b9a5050505050505050505050565b836001600160a01b0316612edd83611b2c565b6001600160a01b031614612f425760405162461bcd60e51b815260206004820152602660248201527f4e46543a207472616e73666572206f6620746f6b656e2074686174206973206e60448201526537ba1037bbb760d11b6064820152608401610ba5565b6001600160a01b038316612fa25760405162461bcd60e51b815260206004820152602160248201527f4e46543a207472616e7366657220746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610ba5565b6000828152600660205260408120556001600160a01b0384166000908152600d60205260408120805460019290612fda908490613d12565b90915550506001600160a01b0383166000908152600d60205260408120805460019290613008908490613ae8565b90915550506000828152600c6020526040902080546001600160a01b0319166001600160a01b0385169081179091553b156130cd576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a0290613088903390889087908790600401613d5e565b6020604051808303816000875af11580156130a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130cb9190613d9a565b505b81836001600160a01b0316856001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050565b80516060908390839061312957613129613ddc565b6000815183516131399190613ae8565b67ffffffffffffffff811115613151576131516135b1565b6040519080825280601f01601f19166020018201604052801561317b576020820181803683370190505b509050806000805b85518210156132235785828151811061319e5761319e613a88565b01602001517fff000000000000000000000000000000000000000000000000000000000000001683826131d081613c09565b9350815181106131e2576131e2613a88565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508161321b81613c09565b925050613183565b600091505b84518210156132c85784828151811061324357613243613a88565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016838261327581613c09565b93508151811061328757613287613a88565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350816132c081613c09565b925050613228565b5090979650505050505050565b6000848152600360205260409020805483918391869081106132f9576132f9613a88565b906000526020600020019182612dda929190613c22565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61336a82826133bb565b5050565b6000818152600360205260408120549003612cca576000818152600360209081526040808320805460018101825590845282842082519384019092529282529091019061336a9082613b49565b6001600160a01b0382166134115760405162461bcd60e51b815260206004820152601d60248201527f4e46543a206d696e7420746f20746865207a65726f20616464726573730000006044820152606401610ba5565b6000818152600c60205260409020546001600160a01b0316156134765760405162461bcd60e51b815260206004820152601960248201527f4e46543a20746f6b656e20616c7265616479206d696e746564000000000000006044820152606401610ba5565b6001600160a01b0382166000908152600d6020526040812080546001929061349f908490613ae8565b90915550506000818152600c602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006020828403121561350f57600080fd5b5035919050565b6000815180845260005b8181101561353c57602081850181015186830182015201613520565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061356f6020830184613516565b9392505050565b6000806040838503121561358957600080fd5b50508035926020909101359150565b803563ffffffff811681146135ac57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156135e2576135e26135b1565b604051601f8501601f19908116603f0116810190828211818310171561360a5761360a6135b1565b8160405280935085815286868601111561362357600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261364e57600080fd5b61356f838335602085016135c7565b6000806040838503121561367057600080fd5b61367983613598565b9150602083013567ffffffffffffffff81111561369557600080fd5b6136a18582860161363d565b9150509250929050565b60008083601f8401126136bd57600080fd5b50813567ffffffffffffffff8111156136d557600080fd5b6020830191508360208285010111156136ed57600080fd5b9250929050565b60008060006040848603121561370957600080fd5b83359250602084013567ffffffffffffffff81111561372757600080fd5b613733868287016136ab565b9497909650939450505050565b60008060006060848603121561375557600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561377a57600080fd5b6137868682870161363d565b9150509250925092565b600080600080606085870312156137a657600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156137cb57600080fd5b6137d7878288016136ab565b95989497509550505050565b600081518084526020808501808196508360051b8101915082860160005b8581101561382b578284038952613819848351613516565b98850198935090840190600101613801565b5091979650505050505050565b60208152600061356f60208301846137e3565b602081526000825160208084015261386660408401826137e3565b949350505050565b80356001600160a01b03811681146135ac57600080fd5b60006020828403121561389757600080fd5b61356f8261386e565b600080604083850312156138b357600080fd5b823591506138c360208401613598565b90509250929050565b600080604083850312156138df57600080fd5b82359150602083013567ffffffffffffffff81111561369557600080fd5b60006020828403121561390f57600080fd5b61356f82613598565b60008060006060848603121561392d57600080fd5b61393684613598565b92506139446020850161386e565b9150604084013590509250925092565b60008060006060848603121561396957600080fd5b833567ffffffffffffffff8082111561398157600080fd5b61398d8783880161363d565b945060208601359150808211156139a357600080fd5b506139b08682870161363d565b925050604084013590509250925092565b6000806000606084860312156139d657600080fd5b6139df8461386e565b925060208401359150604084013567ffffffffffffffff811115613a0257600080fd5b8401601f81018613613a1357600080fd5b613786868235602084016135c7565b60008060408385031215613a3557600080fd5b613a3e8361386e565b946020939093013593505050565b60008060408385031215613a5f57600080fd5b613a688361386e565b915060208301358015158114613a7d57600080fd5b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b600181811c90821680613ab257607f821691505b6020821081036118d157634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115611ba057611ba0613ad2565b601f821115610f7657600081815260208120601f850160051c81016020861015613b225750805b601f850160051c820191505b81811015613b4157828155600101613b2e565b505050505050565b815167ffffffffffffffff811115613b6357613b636135b1565b613b7781613b718454613a9e565b84613afb565b602080601f831160018114613bac5760008415613b945750858301515b600019600386901b1c1916600185901b178555613b41565b600085815260208120601f198616915b82811015613bdb57888601518255948401946001909101908401613bbc565b5085821015613bf95787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060018201613c1b57613c1b613ad2565b5060010190565b67ffffffffffffffff831115613c3a57613c3a6135b1565b613c4e83613c488354613a9e565b83613afb565b6000601f841160018114613c825760008515613c6a5750838201355b600019600387901b1c1916600186901b178355613cdc565b600083815260209020601f19861690835b82811015613cb35786850135825560209485019460019092019101613c93565b5086821015613cd05760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b81810381811115611ba057611ba0613ad2565b8082028115828204841417611ba057611ba0613ad2565b600082613d5957634e487b7160e01b600052601260045260246000fd5b500490565b60006001600160a01b03808716835280861660208401525083604083015260806060830152613d906080830184613516565b9695505050505050565b600060208284031215613dac57600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461356f57600080fd5b634e487b7160e01b600052600160045260246000fdfe5175657269656420636c61737320646f6573206e6f74206578697374000000004f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a26469706673582212207bd079fde35ce03bd3e6c357dc3df533a24c8dfe4e7da9f172921452234bb8c764736f6c63430008130033
Deployed ByteCode
0x6080604052600436106103135760003560e01c806370a082311161019a578063b9186d7d116100e1578063c98e0c3c1161008a578063e29fb03611610064578063e29fb036146109b4578063e6470059146109ca578063f2fde38b146109ea57600080fd5b8063c98e0c3c1461092c578063cb177b1e1461094c578063d75d1e661461096c57600080fd5b8063be671058116100bb578063be671058146108bf578063c1940f1b146108df578063c87b56dd1461090c57600080fd5b8063b9186d7d1461085f578063bb0537171461087f578063be45fd621461089f57600080fd5b80638da5cb5b1161014357806395d89b411161011d57806395d89b411461080a5780639de4792e1461081f578063b119490e1461083f57600080fd5b80638da5cb5b146107b65780638e39e18c146107d457806391100695146107f457600080fd5b806378317f3f1161017457806378317f3f146107565780637ab56e521461077657806380483a6a1461079657600080fd5b806370a08231146106c457806373baa651146106e457806374c29ce3146106f757600080fd5b80633e0bb7831161025e578063543dc7fa11610207578063648fbe40116101e1578063648fbe4014610641578063649ccc141461066157806369a13712146106a457600080fd5b8063543dc7fa146105a35780635a3b7e42146105c35780636352211e1461060957600080fd5b80634c1720a4116102385780634c1720a4146105265780634edea11114610546578063510910bb1461057357600080fd5b80633e0bb783146104b95780634774d93f146104d95780634bb2ddd4146104f957600080fd5b8063290e008c116102c05780633add5fa11161029a5780633add5fa1146104595780633c65b3eb146104795780633d8073f11461049957600080fd5b8063290e008c146103f95780632a6d3f44146104195780633054d9cb1461043957600080fd5b80631d734c8f116102f15780631d734c8f146103935780631f38e654146103b757806325498c75146103d957600080fd5b806302ff368a1461031857806306fdde031461034e5780630eaaf4c814610363575b600080fd5b34801561032457600080fd5b506103386103333660046134fd565b610a0a565b604051610345919061355c565b60405180910390f35b34801561035a57600080fd5b50610338610ac4565b34801561036f57600080fd5b5061038361037e3660046134fd565b610b56565b6040519015158152602001610345565b34801561039f57600080fd5b506103a960115481565b604051908152602001610345565b3480156103c357600080fd5b506103d76103d2366004613576565b610d6d565b005b3480156103e557600080fd5b506103d76103f436600461365d565b610e05565b34801561040557600080fd5b506103d76104143660046136f4565b610efa565b34801561042557600080fd5b506103836104343660046136f4565b610f7b565b34801561044557600080fd5b506103d7610454366004613740565b611089565b34801561046557600080fd5b506103d7610474366004613790565b61118b565b34801561048557600080fd5b506103a96104943660046134fd565b6111e5565b3480156104a557600080fd5b506103d76104b4366004613790565b6112d7565b3480156104c557600080fd5b506103386104d4366004613576565b611571565b3480156104e557600080fd5b506103d76104f4366004613740565b61162a565b34801561050557600080fd5b506105196105143660046134fd565b611799565b6040516103459190613838565b34801561053257600080fd5b50610338610541366004613576565b6118d7565b34801561055257600080fd5b506105666105613660046134fd565b6119d5565b604051610345919061384b565b34801561057f57600080fd5b5061038361058e366004613885565b60016020526000908152604090205460ff1681565b3480156105af57600080fd5b506103a96105be3660046134fd565b611aca565b3480156105cf57600080fd5b5060408051808201909152600b81527f43616c6c6973746f4e46540000000000000000000000000000000000000000006020820152610338565b34801561061557600080fd5b506106296106243660046134fd565b611b2c565b6040516001600160a01b039091168152602001610345565b34801561064d57600080fd5b506103d761065c3660046138a0565b611ba6565b34801561066d57600080fd5b5061068161067c3660046134fd565b611c16565b604080519384526001600160a01b03909216602084015290820152606001610345565b3480156106b057600080fd5b506103d76106bf3660046138cc565b611cbd565b3480156106d057600080fd5b506103a96106df366004613885565b611dc2565b6103d76106f23660046136f4565b611e5c565b34801561070357600080fd5b506107376107123660046138fd565b600460205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b039093168352602083019190915201610345565b34801561076257600080fd5b506103d76107713660046138a0565b6121c8565b34801561078257600080fd5b50610338610791366004613576565b612238565b3480156107a257600080fd5b506103d76107b13660046134fd565b6122f7565b3480156107c257600080fd5b506000546001600160a01b0316610629565b3480156107e057600080fd5b506103d76107ef366004613918565b6123b7565b34801561080057600080fd5b506103a960055481565b34801561081657600080fd5b5061033861243a565b34801561082b57600080fd5b5061033861083a366004613576565b612449565b34801561084b57600080fd5b506103d761085a366004613954565b6124c8565b34801561086b57600080fd5b506103a961087a3660046134fd565b6125e1565b34801561088b57600080fd5b506103d761089a366004613790565b612669565b3480156108ab57600080fd5b506103836108ba3660046139c1565b6126bd565b3480156108cb57600080fd5b506103d76108da366004613576565b6126fa565b3480156108eb57600080fd5b506103a96108fa3660046134fd565b60106020526000908152604090205481565b34801561091857600080fd5b506103386109273660046134fd565b612798565b34801561093857600080fd5b50610383610947366004613a22565b6128b1565b34801561095857600080fd5b506103d7610967366004613a4c565b612a42565b34801561097857600080fd5b5061099f6109873660046134fd565b600f6020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610345565b3480156109c057600080fd5b506103a960095481565b3480156109d657600080fd5b506105196109e53660046134fd565b612ae6565b3480156109f657600080fd5b506103d7610a05366004613885565b612bfd565b6000818152600360205260408120805460609290610a2a57610a2a613a88565b906000526020600020018054610a3f90613a9e565b80601f0160208091040260200160405190810160405280929190818152602001828054610a6b90613a9e565b8015610ab85780601f10610a8d57610100808354040283529160200191610ab8565b820191906000526020600020905b815481529060010190602001808311610a9b57829003601f168201915b50505050509050919050565b6060600a8054610ad390613a9e565b80601f0160208091040260200160405190810160405280929190818152602001828054610aff90613a9e565b8015610b4c5780601f10610b2157610100808354040283529160200191610b4c565b820191906000526020600020905b815481529060010190602001808311610b2f57829003601f168201915b5050505050905090565b60006002805403610bae5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002805560008080610bbf85611c16565b91945092509050336001600160a01b03831614610c445760405162461bcd60e51b815260206004820152602260248201527f43616e206e6f7420776974686472617720736f6d656f6e6520656c736573206260448201527f69640000000000000000000000000000000000000000000000000000000000006064820152608401610ba5565b600554610c519082613ae8565b4211610c9f5760405162461bcd60e51b815260206004820152601260248201527f4269642069732074696d652d6c6f636b656400000000000000000000000000006044820152606401610ba5565b6040516000906001600160a01b0384169085156108fc0290869084818181858888f160008b81526007602052604080822080546001600160a01b0319168155600181018390556002018290555191965094508a93507f223d0d5db4846341da7a5cc902b1a7c597e63b6c73b1c6267dc931d290c7affb9250610d53915060208082526018908201527f3078373736393734363836343732363137373432363936340000000000000000604082015260600190565b60405180910390a360019450505050506001600255919050565b6000546001600160a01b03163314610db55760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b60008281526010602090815260409182902083905581518481529081018390527fa8b2c0f94a578b5a88c9c7d9242237165ea684a64cd32968c7f0dd6edd22dbe091015b60405180910390a15050565b6000546001600160a01b03163314610e4d5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6011546000908152600e6020908152604082208054600181018255908352912001610e788282613b49565b50601180546000908152600f6020526040808220805463ffffffff871663ffffffff19909116179055915491517f949a1ec513916b5e46ab2c5681369a4651bba074831b8da896b06a94e8d041b692610ed992908252602082015260400190565b60405180910390a160118054906000610ef183613c09565b91905055505050565b33610f0d6000546001600160a01b031690565b6001600160a01b03161480610f3157503360009081526001602052604090205460ff165b610f6b5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b610f76838383612ccd565b505050565b6000610f8684611b2c565b6001600160a01b0316336001600160a01b03161461100c5760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f6e6c79206f776e65722063616e206368616e6765204e4654206360448201527f6f6e74656e7400000000000000000000000000000000000000000000000000006064820152608401610ba5565b60008481526003602052604081208054859285929161102d5761102d613a88565b906000526020600020019182611044929190613c22565b5060408051858152600060208201527f0fe79316286f6a1e5cf32c3c4ff10c2a66b9cd66da3353db3789c4042ffb44ee91015b60405180910390a15060019392505050565b6000546001600160a01b031633146110d15760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b8260115481106111115760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000848152600e6020526040902080548391908590811061113457611134613a88565b90600052602060002001908161114a9190613b49565b5060408051858152602081018590527f949a1ec513916b5e46ab2c5681369a4651bba074831b8da896b06a94e8d041b691015b60405180910390a150505050565b6000546001600160a01b031633146111d35760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6111df84848484612d4b565b50505050565b60008160115481106112275760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b3360009081526001602052604090205460ff166112865760405162461bcd60e51b815260206004820152601460248201527f4d696e74657220726f6c652072657175697265640000000000000000000000006044820152606401610ba5565b61128e612e11565b6000818152601060209081526040808320879055958252600f8152858220548383526008909152949020805463ffffffff191663ffffffff909516949094179093555090919050565b8382828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060025460011901915061136390505760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ba5565b600280553361137187611b2c565b6001600160a01b0316146113ed5760405162461bcd60e51b815260206004820152602c60248201527f53657474696e672061736b73206973206f6e6c7920616c6c6f77656420666f7260448201527f206f776e6564204e4654732100000000000000000000000000000000000000006064820152608401610ba5565b6000868152600660205260409081902086905551859087907f403cbda48c4d379b57469bea093b63817816d893b467842ee46fd1c3c29c05f8906114349088908890613ce3565b60405180910390a3600160025560008061144d84611c16565b5091509150600061145d856125e1565b11801561147257508161146f856125e1565b11155b156115675760006114838386612e43565b61148d9084613d12565b905061149885611b2c565b6001600160a01b0316826001600160a01b0316867fc9b9afd9684b23c6b22a41016c08e8954ac118220c0a52f00b8774c46580e9a3846040516114dd91815260200190565b60405180910390a460006114f086611b2c565b6001600160a01b03166108fc839081150290604051600060405180830381858888f160008b815260076020908152604080832080546001600160a01b03191681556001810184905560020183905560069091528120559450611564935061155c9250899150611b2c9050565b848888612eca565b50505b5050505050505050565b600e602052816000526040600020818154811061158d57600080fd5b906000526020600020016000915091505080546115a990613a9e565b80601f01602080910402602001604051908101604052809291908181526020018280546115d590613a9e565b80156116225780601f106115f757610100808354040283529160200191611622565b820191906000526020600020905b81548152906001019060200180831161160557829003601f168201915b505050505081565b6000546001600160a01b031633146116725760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b8260115481106116b25760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000848152600e602052604090208054611779918491869081106116d8576116d8613a88565b9060005260206000200180546116ed90613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461171990613a9e565b80156117665780601f1061173b57610100808354040283529160200191611766565b820191906000526020600020905b81548152906001019060200180831161174957829003601f168201915b505050505061311490919063ffffffff16565b6000858152600e6020526040902080548590811061113457611134613a88565b6000818152601060205260409020546011546060919081106117eb5760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000838152601060209081526040808320548352600e825280832080548251818502810185019093528083529193909284015b828210156118ca57838290600052602060002001805461183d90613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461186990613a9e565b80156118b65780601f1061188b576101008083540402835291602001916118b6565b820191906000526020600020905b81548152906001019060200180831161189957829003601f168201915b50505050508152602001906001019061181e565b5050505091505b50919050565b60608260115481106119195760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000848152600e6020526040902080548490811061193957611939613a88565b90600052602060002001805461194e90613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461197a90613a9e565b80156119c75780601f1061199c576101008083540402835291602001916119c7565b820191906000526020600020905b8154815290600101906020018083116119aa57829003601f168201915b505050505091505092915050565b604080516020808201835260608252600084815260038252838120845181548085028201870187529381018481529495909491938593859285015b82821015611abc578382906000526020600020018054611a2f90613a9e565b80601f0160208091040260200160405190810160405280929190818152602001828054611a5b90613a9e565b8015611aa85780601f10611a7d57610100808354040283529160200191611aa8565b820191906000526020600020905b815481529060010190602001808311611a8b57829003601f168201915b505050505081526020019060010190611a10565b505050915250909392505050565b6000818152601060205260408120546011548110611b185760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b505060009081526010602052604090205490565b6000818152600c60205260408120546001600160a01b031680611ba05760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610ba5565b92915050565b6000546001600160a01b03163314611bee5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b600091825260086020526040909120805463ffffffff191663ffffffff909216919091179055565b6000818152600c6020526040812054819081906001600160a01b031680611c8e5760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610ba5565b5050506000918252506007602052604090206001810154815460029092015490926001600160a01b0390921691565b6000546001600160a01b03163314611d055760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b816011548110611d455760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000838152600e6020908152604082208054600181018255908352912001611d6d8382613b49565b506000838152600e6020526040812054611d8990600190613d12565b60408051868152602081018390529192507f949a1ec513916b5e46ab2c5681369a4651bba074831b8da896b06a94e8d041b6910161117d565b60006001600160a01b038216611e405760405162461bcd60e51b815260206004820152602760248201527f4e46543a2062616c616e636520717565727920666f7220746865207a65726f2060448201527f61646472657373000000000000000000000000000000000000000000000000006064820152608401610ba5565b506001600160a01b03166000908152600d602052604090205490565b8282828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050600254600119019150611ee890505760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ba5565b60028055600080611ef887611c16565b5091509150813411611f715760405162461bcd60e51b8152602060048201526024808201527f4e657720626964206d7573742065786365656420746865206578697374696e6760448201527f206f6e65000000000000000000000000000000000000000000000000000000006064820152608401610ba5565b6000808315611fa1576040516001600160a01b0384169085156108fc029086906000818181858888f19450505050505b34611fab8a6125e1565b108015611fc057506000611fbe8a6125e1565b115b15611fd557611fce896125e1565b9150611fd9565b3491505b600089815260076020526040908190206001810184905580546001600160a01b03191633178155426002909101555182908a907f223d0d5db4846341da7a5cc902b1a7c597e63b6c73b1c6267dc931d290c7affb9061203b908c908c90613ce3565b60405180910390a33461204d8a6125e1565b108015612062575060006120608a6125e1565b115b1561209757336108fc6120748b6125e1565b61207e9034613d12565b6040518115909202916000818181858888f19450505050505b505060016002555060009050806120ad84611c16565b509150915060006120bd856125e1565b1180156120d25750816120cf856125e1565b11155b156121bf5760006120e38386612e43565b6120ed9084613d12565b90506120f885611b2c565b6001600160a01b0316826001600160a01b0316867fc9b9afd9684b23c6b22a41016c08e8954ac118220c0a52f00b8774c46580e9a38460405161213d91815260200190565b60405180910390a4600061215086611b2c565b6001600160a01b03166108fc839081150290604051600060405180830381858888f160008b815260076020908152604080832080546001600160a01b031916815560018101849055600201839055600690915281205594506121bc935061155c9250899150611b2c9050565b50505b50505050505050565b6000546001600160a01b031633146122105760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6000918252600f6020526040909120805463ffffffff191663ffffffff909216919091179055565b60008281526003602052604090208054606091908390811061225c5761225c613a88565b90600052602060002001805461227190613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461229d90613a9e565b80156122ea5780601f106122bf576101008083540402835291602001916122ea565b820191906000526020600020905b8154815290600101906020018083116122cd57829003601f168201915b5050505050905092915050565b6000546001600160a01b0316331461233f5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b80601154811061237f5760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000828152600e602090815260408083208054600181018255908452828420825193840190925292825290910190610f769082613b49565b6000546001600160a01b031633146123ff5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b63ffffffff909216600090815260046020526040902080546001600160a01b039092166001600160a01b031990921691909117815560010155565b6060600b8054610ad390613a9e565b60008281526010602052604090205460115460609190811061249b5760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000848152601060209081526040808320548352600e909152902080548490811061193957611939613a88565b6000546001600160a01b0316156125215760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610ba5565b600080546001600160a01b0319163390811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a362015180600555600a6125738482613b49565b50600b6125808382613b49565b506000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec80546001600160a01b031916331790557f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed555050565b6000818152600c60205260408120546001600160a01b0316806126555760405162461bcd60e51b815260206004820152602660248201527f4e46543a206f776e657220717565727920666f72206e6f6e6578697374656e74604482015265103a37b5b2b760d11b6064820152608401610ba5565b505060009081526006602052604090205490565b6000546001600160a01b031633146126b15760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6111df848484846132d5565b60006126cb33858585612eca565b7f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad97682604051611077919061355c565b6000546001600160a01b031633146127425760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b60005b82811015610f76576000828152600e6020908152604080832080546001810182559084528284208251938401909252928252909101906127859082613b49565b508061279081613c09565b915050612745565b6000818152601060205260409020546011546060919081106127ea5760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000838152601060209081526040808320548352600e9091528120805490919061281657612816613a88565b90600052602060002001805461282b90613a9e565b80601f016020809104026020016040519081016040528092919081815260200182805461285790613a9e565b80156128a45780601f10612879576101008083540402835291602001916128a4565b820191906000526020600020905b81548152906001019060200180831161288757829003601f168201915b5050505050915050919050565b6000336128bd83611b2c565b6001600160a01b0316146129225760405162461bcd60e51b815260206004820152602660248201527f4e46543a207472616e73666572206f6620746f6b656e2074686174206973206e60448201526537ba1037bbb760d11b6064820152608401610ba5565b6001600160a01b0383166129825760405162461bcd60e51b815260206004820152602160248201527f4e46543a207472616e7366657220746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610ba5565b600082815260066020526040812055336000908152600d602052604081208054600192906129b1908490613d12565b90915550506001600160a01b0383166000908152600d602052604081208054600192906129df908490613ae8565b90915550506000828152600c602052604080822080546001600160a01b0319166001600160a01b0387169081179091559051849233917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9190a450600192915050565b6000546001600160a01b03163314612a8a5760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f6b0f890a293c8f56a7635ad061c90250965b8af8e8bdbeb56d434b97281a74629101610df9565b6060816011548110612b285760405162461bcd60e51b815260206004820152601c6024820152600080516020613df38339815191526044820152606401610ba5565b6000838152600e6020908152604080832080548251818502810185019093528083529193909284015b828210156118ca578382906000526020600020018054612b7090613a9e565b80601f0160208091040260200160405190810160405280929190818152602001828054612b9c90613a9e565b8015612be95780601f10612bbe57610100808354040283529160200191612be9565b820191906000526020600020905b815481529060010190602001808311612bcc57829003601f168201915b505050505081526020019060010190612b51565b6000546001600160a01b03163314612c455760405162461bcd60e51b81526020600482018190526024820152600080516020613e138339815191526044820152606401610ba5565b6001600160a01b038116612cc15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ba5565b612cca81613310565b50565b600083815260036020908152604082208054600181018255908352912001612cf6828483613c22565b50600083815260036020526040812054612d1290600190613d12565b60408051868152602081018390529192507f0fe79316286f6a1e5cf32c3c4ff10c2a66b9cd66da3353db3789c4042ffb44ee910161117d565b612da482828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052508981526003602052604090208054909350889250821090506116d8576116d8613a88565b6000858152600360205260409020805485908110612dc457612dc4613a88565b906000526020600020019081612dda9190613b49565b5060408051858152602081018590527f0fe79316286f6a1e5cf32c3c4ff10c2a66b9cd66da3353db3789c4042ffb44ee910161117d565b6000612e1f33600954613360565b50600980549081906000612e3283613c09565b9190505550612e408161336e565b90565b60008181526008602090815260408083205463ffffffff168084526004909252822080546001909101546001600160a01b039091169083620186a0612e888389613d25565b612e929190613d3c565b90506000836001600160a01b03166108fc839081150290604051600060405180830381858888f150949b9a5050505050505050505050565b836001600160a01b0316612edd83611b2c565b6001600160a01b031614612f425760405162461bcd60e51b815260206004820152602660248201527f4e46543a207472616e73666572206f6620746f6b656e2074686174206973206e60448201526537ba1037bbb760d11b6064820152608401610ba5565b6001600160a01b038316612fa25760405162461bcd60e51b815260206004820152602160248201527f4e46543a207472616e7366657220746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610ba5565b6000828152600660205260408120556001600160a01b0384166000908152600d60205260408120805460019290612fda908490613d12565b90915550506001600160a01b0383166000908152600d60205260408120805460019290613008908490613ae8565b90915550506000828152600c6020526040902080546001600160a01b0319166001600160a01b0385169081179091553b156130cd576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a0290613088903390889087908790600401613d5e565b6020604051808303816000875af11580156130a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130cb9190613d9a565b505b81836001600160a01b0316856001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050565b80516060908390839061312957613129613ddc565b6000815183516131399190613ae8565b67ffffffffffffffff811115613151576131516135b1565b6040519080825280601f01601f19166020018201604052801561317b576020820181803683370190505b509050806000805b85518210156132235785828151811061319e5761319e613a88565b01602001517fff000000000000000000000000000000000000000000000000000000000000001683826131d081613c09565b9350815181106131e2576131e2613a88565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508161321b81613c09565b925050613183565b600091505b84518210156132c85784828151811061324357613243613a88565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016838261327581613c09565b93508151811061328757613287613a88565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350816132c081613c09565b925050613228565b5090979650505050505050565b6000848152600360205260409020805483918391869081106132f9576132f9613a88565b906000526020600020019182612dda929190613c22565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61336a82826133bb565b5050565b6000818152600360205260408120549003612cca576000818152600360209081526040808320805460018101825590845282842082519384019092529282529091019061336a9082613b49565b6001600160a01b0382166134115760405162461bcd60e51b815260206004820152601d60248201527f4e46543a206d696e7420746f20746865207a65726f20616464726573730000006044820152606401610ba5565b6000818152600c60205260409020546001600160a01b0316156134765760405162461bcd60e51b815260206004820152601960248201527f4e46543a20746f6b656e20616c7265616479206d696e746564000000000000006044820152606401610ba5565b6001600160a01b0382166000908152600d6020526040812080546001929061349f908490613ae8565b90915550506000818152600c602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006020828403121561350f57600080fd5b5035919050565b6000815180845260005b8181101561353c57602081850181015186830182015201613520565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061356f6020830184613516565b9392505050565b6000806040838503121561358957600080fd5b50508035926020909101359150565b803563ffffffff811681146135ac57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156135e2576135e26135b1565b604051601f8501601f19908116603f0116810190828211818310171561360a5761360a6135b1565b8160405280935085815286868601111561362357600080fd5b858560208301376000602087830101525050509392505050565b600082601f83011261364e57600080fd5b61356f838335602085016135c7565b6000806040838503121561367057600080fd5b61367983613598565b9150602083013567ffffffffffffffff81111561369557600080fd5b6136a18582860161363d565b9150509250929050565b60008083601f8401126136bd57600080fd5b50813567ffffffffffffffff8111156136d557600080fd5b6020830191508360208285010111156136ed57600080fd5b9250929050565b60008060006040848603121561370957600080fd5b83359250602084013567ffffffffffffffff81111561372757600080fd5b613733868287016136ab565b9497909650939450505050565b60008060006060848603121561375557600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561377a57600080fd5b6137868682870161363d565b9150509250925092565b600080600080606085870312156137a657600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156137cb57600080fd5b6137d7878288016136ab565b95989497509550505050565b600081518084526020808501808196508360051b8101915082860160005b8581101561382b578284038952613819848351613516565b98850198935090840190600101613801565b5091979650505050505050565b60208152600061356f60208301846137e3565b602081526000825160208084015261386660408401826137e3565b949350505050565b80356001600160a01b03811681146135ac57600080fd5b60006020828403121561389757600080fd5b61356f8261386e565b600080604083850312156138b357600080fd5b823591506138c360208401613598565b90509250929050565b600080604083850312156138df57600080fd5b82359150602083013567ffffffffffffffff81111561369557600080fd5b60006020828403121561390f57600080fd5b61356f82613598565b60008060006060848603121561392d57600080fd5b61393684613598565b92506139446020850161386e565b9150604084013590509250925092565b60008060006060848603121561396957600080fd5b833567ffffffffffffffff8082111561398157600080fd5b61398d8783880161363d565b945060208601359150808211156139a357600080fd5b506139b08682870161363d565b925050604084013590509250925092565b6000806000606084860312156139d657600080fd5b6139df8461386e565b925060208401359150604084013567ffffffffffffffff811115613a0257600080fd5b8401601f81018613613a1357600080fd5b613786868235602084016135c7565b60008060408385031215613a3557600080fd5b613a3e8361386e565b946020939093013593505050565b60008060408385031215613a5f57600080fd5b613a688361386e565b915060208301358015158114613a7d57600080fd5b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b600181811c90821680613ab257607f821691505b6020821081036118d157634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115611ba057611ba0613ad2565b601f821115610f7657600081815260208120601f850160051c81016020861015613b225750805b601f850160051c820191505b81811015613b4157828155600101613b2e565b505050505050565b815167ffffffffffffffff811115613b6357613b636135b1565b613b7781613b718454613a9e565b84613afb565b602080601f831160018114613bac5760008415613b945750858301515b600019600386901b1c1916600185901b178555613b41565b600085815260208120601f198616915b82811015613bdb57888601518255948401946001909101908401613bbc565b5085821015613bf95787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060018201613c1b57613c1b613ad2565b5060010190565b67ffffffffffffffff831115613c3a57613c3a6135b1565b613c4e83613c488354613a9e565b83613afb565b6000601f841160018114613c825760008515613c6a5750838201355b600019600387901b1c1916600186901b178355613cdc565b600083815260209020601f19861690835b82811015613cb35786850135825560209485019460019092019101613c93565b5086821015613cd05760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b81810381811115611ba057611ba0613ad2565b8082028115828204841417611ba057611ba0613ad2565b600082613d5957634e487b7160e01b600052601260045260246000fd5b500490565b60006001600160a01b03808716835280861660208401525083604083015260806060830152613d906080830184613516565b9695505050505050565b600060208284031215613dac57600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461356f57600080fd5b634e487b7160e01b600052600160045260246000fdfe5175657269656420636c61737320646f6573206e6f74206578697374000000004f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a26469706673582212207bd079fde35ce03bd3e6c357dc3df533a24c8dfe4e7da9f172921452234bb8c764736f6c63430008130033