Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- ArianeeSmartAsset
- Optimization enabled
- true
- Compiler version
- v0.5.6+commit.b259423e
- Verified at
- 2019-06-25T08:28:43.835782Z
Constructor Arguments
000000000000000000000000d3eee7f8e8021db24825c3457d5479f2b57f40ef
Arg [0] (address) : <a href=/poa/core/address/0xd3eee7f8e8021db24825c3457d5479f2b57f40ef>0xd3eee7f8e8021db24825c3457d5479f2b57f40ef</a>
Contract source code
// File: @0xcert/ethereum-utils-contracts/src/contracts/math/safe-math.sol pragma solidity 0.5.6; /** * @dev Math operations with safety checks that throw on error. This contract is based on the * source code at: * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol. */ library SafeMath { /** * @dev Error constants. */ string constant OVERFLOW = "008001"; string constant SUBTRAHEND_GREATER_THEN_MINUEND = "008002"; string constant DIVISION_BY_ZERO = "008003"; /** * @dev Multiplies two numbers, reverts on overflow. * @param _factor1 Factor number. * @param _factor2 Factor number. * @return The product of the two factors. */ function mul( uint256 _factor1, uint256 _factor2 ) internal pure returns (uint256 product) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (_factor1 == 0) { return 0; } product = _factor1 * _factor2; require(product / _factor1 == _factor2, OVERFLOW); } /** * @dev Integer division of two numbers, truncating the quotient, reverts on division by zero. * @param _dividend Dividend number. * @param _divisor Divisor number. * @return The quotient. */ function div( uint256 _dividend, uint256 _divisor ) internal pure returns (uint256 quotient) { // Solidity automatically asserts when dividing by 0, using all gas. require(_divisor > 0, DIVISION_BY_ZERO); quotient = _dividend / _divisor; // assert(_dividend == _divisor * quotient + _dividend % _divisor); // There is no case in which this doesn't hold. } /** * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). * @param _minuend Minuend number. * @param _subtrahend Subtrahend number. * @return Difference. */ function sub( uint256 _minuend, uint256 _subtrahend ) internal pure returns (uint256 difference) { require(_subtrahend <= _minuend, SUBTRAHEND_GREATER_THEN_MINUEND); difference = _minuend - _subtrahend; } /** * @dev Adds two numbers, reverts on overflow. * @param _addend1 Number. * @param _addend2 Number. * @return Sum. */ function add( uint256 _addend1, uint256 _addend2 ) internal pure returns (uint256 sum) { sum = _addend1 + _addend2; require(sum >= _addend1, OVERFLOW); } /** * @dev Divides two numbers and returns the remainder (unsigned integer modulo), reverts when * dividing by zero. * @param _dividend Number. * @param _divisor Number. * @return Remainder. */ function mod( uint256 _dividend, uint256 _divisor ) internal pure returns (uint256 remainder) { require(_divisor != 0, DIVISION_BY_ZERO); remainder = _dividend % _divisor; } } // File: @0xcert/ethereum-utils-contracts/src/contracts/permission/abilitable.sol pragma solidity 0.5.6; /** * @title Contract for setting abilities. * @dev For optimization purposes the abilities are represented as a bitfield. Maximum number of * abilities is therefore 256. This is an example(for simplicity is made for max 8 abilities) of how * this works. * 00000001 Ability A - number representation 1 * 00000010 Ability B - number representation 2 * 00000100 Ability C - number representation 4 * 00001000 Ability D - number representation 8 * 00010000 Ability E - number representation 16 * etc ... * To grant abilities B and C, we would need a bitfield of 00000110 which is represented by number * 6, in other words, the sum of abilities B and C. The same concept works for revoking abilities * and checking if someone has multiple abilities. */ contract Abilitable { using SafeMath for uint; /** * @dev Error constants. */ string constant NOT_AUTHORIZED = "017001"; string constant CANNOT_REVOKE_OWN_SUPER_ABILITY = "017002"; string constant INVALID_INPUT = "017003"; /** * @dev Ability 1 (00000001) is a reserved ability called super ability. It is an * ability to grant or revoke abilities of other accounts. Other abilities are determined by the * implementing contract. */ uint8 constant SUPER_ABILITY = 1; /** * @dev Maps address to ability ids. */ mapping(address => uint256) public addressToAbility; /** * @dev Emits when an address is granted an ability. * @param _target Address to which we are granting abilities. * @param _abilities Number representing bitfield of abilities we are granting. */ event GrantAbilities( address indexed _target, uint256 indexed _abilities ); /** * @dev Emits when an address gets an ability revoked. * @param _target Address of which we are revoking an ability. * @param _abilities Number representing bitfield of abilities we are revoking. */ event RevokeAbilities( address indexed _target, uint256 indexed _abilities ); /** * @dev Guarantees that msg.sender has certain abilities. */ modifier hasAbilities( uint256 _abilities ) { require(_abilities > 0, INVALID_INPUT); require( addressToAbility[msg.sender] & _abilities == _abilities, NOT_AUTHORIZED ); _; } /** * @dev Contract constructor. * Sets SUPER_ABILITY ability to the sender account. */ constructor() public { addressToAbility[msg.sender] = SUPER_ABILITY; emit GrantAbilities(msg.sender, SUPER_ABILITY); } /** * @dev Grants specific abilities to specified address. * @param _target Address to grant abilities to. * @param _abilities Number representing bitfield of abilities we are granting. */ function grantAbilities( address _target, uint256 _abilities ) external hasAbilities(SUPER_ABILITY) { addressToAbility[_target] |= _abilities; emit GrantAbilities(_target, _abilities); } /** * @dev Unassigns specific abilities from specified address. * @param _target Address of which we revoke abilites. * @param _abilities Number representing bitfield of abilities we are revoking. * @param _allowSuperRevoke Additional check that prevents you from removing your own super * ability by mistake. */ function revokeAbilities( address _target, uint256 _abilities, bool _allowSuperRevoke ) external hasAbilities(SUPER_ABILITY) { if (!_allowSuperRevoke && msg.sender == _target) { require((_abilities & 1) == 0, CANNOT_REVOKE_OWN_SUPER_ABILITY); } addressToAbility[_target] &= ~_abilities; emit RevokeAbilities(_target, _abilities); } /** * @dev Check if an address has a specific ability. Throws if checking for 0. * @param _target Address for which we want to check if it has a specific abilities. * @param _abilities Number representing bitfield of abilities we are checking. */ function isAble( address _target, uint256 _abilities ) external view returns (bool) { require(_abilities > 0, INVALID_INPUT); return (addressToAbility[_target] & _abilities) == _abilities; } } // File: @0xcert/ethereum-utils-contracts/src/contracts/permission/ownable.sol pragma solidity 0.5.6; /** * @dev The contract has an owner address, and provides basic authorization control whitch * simplifies the implementation of user permissions. This contract is based on the source code at: * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Ownable.sol */ contract Ownable { /** * @dev Error constants. */ string constant NOT_OWNER = "018001"; string constant ZERO_ADDRESS = "018002"; /** * @dev Address of the owner. */ address public owner; /** * @dev An event which is triggered when the owner is changed. * @param previousOwner The address of the previous owner. * @param newOwner The address of the new owner. */ event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev The constructor sets the original `owner` of the contract to the sender account. */ constructor() public { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner, NOT_OWNER); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param _newOwner The address to transfer ownership to. */ function transferOwnership( address _newOwner ) public onlyOwner { require(_newOwner != address(0), ZERO_ADDRESS); emit OwnershipTransferred(owner, _newOwner); owner = _newOwner; } } // File: contracts/Pausable.sol pragma solidity 0.5.6; /** * @title Pausable * @dev Base contract which allows children to implement an emergency stop mechanism. */ contract Pausable is Ownable { event Pause(); event Unpause(); bool public paused = false; /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!paused); _; } /** * @dev Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { require(paused); _; } /** * @dev called by the owner to pause, triggers stopped state */ function pause() onlyOwner whenNotPaused public { paused = true; emit Pause(); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() onlyOwner whenPaused public { paused = false; emit Unpause(); } } // File: contracts/ECDSA.sol pragma solidity 0.5.6; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * (.note) This call _does not revert_ if the signature is invalid, or * if the signer is otherwise unable to be retrieved. In those scenarios, * the zero address is returned. * * (.warning) `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise) * be too long), and then calling `toEthSignedMessageHash` on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { return (address(0)); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return address(0); } if (v != 27 && v != 28) { return address(0); } // If the signature is valid (and not malleable), return the signer address return ecrecover(hash, v, r, s); } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * [`eth_sign`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign) * JSON-RPC method. * * See `recover`. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } } // File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721.sol pragma solidity 0.5.6; /** * @dev ERC-721 non-fungible token standard. * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. */ interface ERC721 { /** * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any * number of NFTs may be created and assigned without emitting Transfer. At the time of any * transfer, the approved address for that NFT (if any) is reset to none. */ event Transfer( address indexed _from, address indexed _to, uint256 indexed _tokenId ); /** * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero * address indicates there is no approved address. When a Transfer event emits, this also * indicates that the approved address for that NFT (if any) is reset to none. */ event Approval( address indexed _owner, address indexed _approved, uint256 indexed _tokenId ); /** * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage * all NFTs of the owner. */ event ApprovalForAll( address indexed _owner, address indexed _operator, bool _approved ); /** * @dev Transfers the ownership of an NFT from one address to another address. * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this * function checks if `_to` is a smart contract (code size > 0). If so, it calls * `onERC721Received` on `_to` and throws if the return value is not * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`. * @param _from The current owner of the NFT. * @param _to The new owner. * @param _tokenId The NFT to transfer. * @param _data Additional data with no specified format, sent in call to `_to`. */ function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes calldata _data ) external; /** * @dev Transfers the ownership of an NFT from one address to another address. * @notice This works identically to the other function with an extra data parameter, except this * function just sets data to "" * @param _from The current owner of the NFT. * @param _to The new owner. * @param _tokenId The NFT to transfer. */ function safeTransferFrom( address _from, address _to, uint256 _tokenId ) external; /** * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero * address. Throws if `_tokenId` is not a valid NFT. * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else * they mayb be permanently lost. * @param _from The current owner of the NFT. * @param _to The new owner. * @param _tokenId The NFT to transfer. */ function transferFrom( address _from, address _to, uint256 _tokenId ) external; /** * @dev Set or reaffirm the approved address for an NFT. * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is * the current NFT owner, or an authorized operator of the current owner. * @param _approved The new approved NFT controller. * @param _tokenId The NFT to approve. */ function approve( address _approved, uint256 _tokenId ) external; /** * @dev Enables or disables approval for a third party ("operator") to manage all of * `msg.sender`'s assets. It also emits the ApprovalForAll event. * @notice The contract MUST allow multiple operators per owner. * @param _operator Address to add to the set of authorized operators. * @param _approved True if the operators is approved, false to revoke approval. */ function setApprovalForAll( address _operator, bool _approved ) external; /** * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are * considered invalid, and this function throws for queries about the zero address. * @param _owner Address for whom to query the balance. * @return Balance of _owner. */ function balanceOf( address _owner ) external view returns (uint256); /** * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered * invalid, and queries about them do throw. * @param _tokenId The identifier for an NFT. * @return Address of _tokenId owner. */ function ownerOf( uint256 _tokenId ) external view returns (address); /** * @dev Get the approved address for a single NFT. * @notice Throws if `_tokenId` is not a valid NFT. * @param _tokenId The NFT to find the approved address for. * @return Address that _tokenId is approved for. */ function getApproved( uint256 _tokenId ) external view returns (address); /** * @dev Returns true if `_operator` is an approved operator for `_owner`, false otherwise. * @param _owner The address that owns the NFTs. * @param _operator The address that acts on behalf of the owner. * @return True if approved for all, false otherwise. */ function isApprovedForAll( address _owner, address _operator ) external view returns (bool); } // File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-metadata.sol pragma solidity 0.5.6; /** * @dev Optional metadata extension for ERC-721 non-fungible token standard. * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. */ interface ERC721Metadata { /** * @dev Returns a descriptive name for a collection of NFTs in this contract. * @return Representing name. */ function name() external view returns (string memory _name); /** * @dev Returns a abbreviated name for a collection of NFTs in this contract. * @return Representing symbol. */ function symbol() external view returns (string memory _symbol); /** * @dev Returns a distinct Uniform Resource Identifier (URI) for a given asset. It Throws if * `_tokenId` is not a valid NFT. URIs are defined in RFC3986. The URI may point to a JSON file * that conforms to the "ERC721 Metadata JSON Schema". * @return URI of _tokenId. */ function tokenURI(uint256 _tokenId) external view returns (string memory); } // File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-enumerable.sol pragma solidity 0.5.6; /** * @dev Optional enumeration extension for ERC-721 non-fungible token standard. * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. */ interface ERC721Enumerable { /** * @dev Returns a count of valid NFTs tracked by this contract, where each one of them has an * assigned and queryable owner not equal to the zero address. * @return Total supply of NFTs. */ function totalSupply() external view returns (uint256); /** * @dev Returns the token identifier for the `_index`th NFT. Sort order is not specified. * @param _index A counter less than `totalSupply()`. * @return Token id. */ function tokenByIndex( uint256 _index ) external view returns (uint256); /** * @dev Returns the token identifier for the `_index`th NFT assigned to `_owner`. Sort order is * not specified. It throws if `_index` >= `balanceOf(_owner)` or if `_owner` is the zero address, * representing invalid NFTs. * @param _owner An address where we are interested in NFTs owned by them. * @param _index A counter less than `balanceOf(_owner)`. * @return Token id. */ function tokenOfOwnerByIndex( address _owner, uint256 _index ) external view returns (uint256); } // File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-token-receiver.sol pragma solidity 0.5.6; /** * @dev ERC-721 interface for accepting safe transfers. * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. */ interface ERC721TokenReceiver { /** * @dev Handle the receipt of a NFT. The ERC721 smart contract calls this function on the * recipient after a `transfer`. This function MAY throw to revert and reject the transfer. Return * of other than the magic value MUST result in the transaction being reverted. * Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` unless throwing. * @notice The contract address is always the message sender. A wallet/broker/auction application * MUST implement the wallet interface if it will accept safe transfers. * @param _operator The address which called `safeTransferFrom` function. * @param _from The address which previously owned the token. * @param _tokenId The NFT identifier which is being transferred. * @param _data Additional data with no specified format. * @return Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. */ function onERC721Received( address _operator, address _from, uint256 _tokenId, bytes calldata _data ) external returns(bytes4); } // File: @0xcert/ethereum-utils-contracts/src/contracts/utils/erc165.sol pragma solidity 0.5.6; /** * @dev A standard for detecting smart contract interfaces. * See: https://eips.ethereum.org/EIPS/eip-165. */ interface ERC165 { /** * @dev Checks if the smart contract implements a specific interface. * @notice This function uses less than 30,000 gas. * @param _interfaceID The interface identifier, as specified in ERC-165. */ function supportsInterface( bytes4 _interfaceID ) external view returns (bool); } // File: @0xcert/ethereum-utils-contracts/src/contracts/utils/supports-interface.sol pragma solidity 0.5.6; /** * @dev Implementation of standard to publish supported interfaces. */ contract SupportsInterface is ERC165 { /** * @dev Mapping of supported intefraces. * @notice You must not set element 0xffffffff to true. */ mapping(bytes4 => bool) internal supportedInterfaces; /** * @dev Contract constructor. */ constructor() public { supportedInterfaces[0x01ffc9a7] = true; // ERC165 } /** * @dev Function to check which interfaces are suported by this contract. * @param _interfaceID Id of the interface. */ function supportsInterface( bytes4 _interfaceID ) external view returns (bool) { return supportedInterfaces[_interfaceID]; } } // File: @0xcert/ethereum-utils-contracts/src/contracts/utils/address-utils.sol pragma solidity 0.5.6; /** * @dev Utility library of inline functions on addresses. */ library AddressUtils { /** * @dev Returns whether the target address is a contract. * @param _addr Address to check. * @return True if _addr is a contract, false if not. */ function isContract( address _addr ) internal view returns (bool addressCheck) { uint256 size; /** * XXX Currently there is no better way to check if there is a contract in an address than to * check the size of the code at that address. * See https://ethereum.stackexchange.com/a/14016/36603 for more details about how this works. * TODO: Check this again before the Serenity release, because all addresses will be * contracts then. */ assembly { size := extcodesize(_addr) } // solhint-disable-line addressCheck = size > 0; } } // File: @0xcert/ethereum-erc721-contracts/src/contracts/nf-token-metadata-enumerable.sol pragma solidity 0.5.6; /** * @dev Optional metadata enumerable implementation for ERC-721 non-fungible token standard. */ contract NFTokenMetadataEnumerable is ERC721, ERC721Metadata, ERC721Enumerable, SupportsInterface { using SafeMath for uint256; using AddressUtils for address; /** * @dev Error constants. */ string constant ZERO_ADDRESS = "006001"; string constant NOT_VALID_NFT = "006002"; string constant NOT_OWNER_OR_OPERATOR = "006003"; string constant NOT_OWNER_APPROWED_OR_OPERATOR = "006004"; string constant NOT_ABLE_TO_RECEIVE_NFT = "006005"; string constant NFT_ALREADY_EXISTS = "006006"; string constant INVALID_INDEX = "006007"; /** * @dev Magic value of a smart contract that can recieve NFT. * Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")). */ bytes4 constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02; /** * @dev A descriptive name for a collection of NFTs. */ string internal nftName; /** * @dev An abbreviated name for NFTs. */ string internal nftSymbol; /** * @dev URI base for NFT metadata. NFT URI is made from base + NFT id. */ string public uriBase; /** * @dev Array of all NFT IDs. */ uint256[] internal tokens; /** * @dev Mapping from token ID its index in global tokens array. */ mapping(uint256 => uint256) internal idToIndex; /** * @dev Mapping from owner to list of owned NFT IDs. */ mapping(address => uint256[]) internal ownerToIds; /** * @dev Mapping from NFT ID to its index in the owner tokens list. */ mapping(uint256 => uint256) internal idToOwnerIndex; /** * @dev A mapping from NFT ID to the address that owns it. */ mapping (uint256 => address) internal idToOwner; /** * @dev Mapping from NFT ID to approved address. */ mapping (uint256 => address) internal idToApproval; /** * @dev Mapping from owner address to mapping of operator addresses. */ mapping (address => mapping (address => bool)) internal ownerToOperators; /** * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any * number of NFTs may be created and assigned without emitting Transfer. At the time of any * transfer, the approved address for that NFT (if any) is reset to none. * @param _from Sender of NFT (if address is zero address it indicates token creation). * @param _to Receiver of NFT (if address is zero address it indicates token destruction). * @param _tokenId The NFT that got transfered. */ event Transfer( address indexed _from, address indexed _to, uint256 indexed _tokenId ); /** * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero * address indicates there is no approved address. When a Transfer event emits, this also * indicates that the approved address for that NFT (if any) is reset to none. * @param _owner Owner of NFT. * @param _approved Address that we are approving. * @param _tokenId NFT which we are approving. */ event Approval( address indexed _owner, address indexed _approved, uint256 indexed _tokenId ); /** * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage * all NFTs of the owner. * @param _owner Owner of NFT. * @param _operator Address to which we are setting operator rights. * @param _approved Status of operator rights(true if operator rights are given and false if * revoked). */ event ApprovalForAll( address indexed _owner, address indexed _operator, bool _approved ); /** * @dev Contract constructor. * @notice When implementing this contract don't forget to set nftName, nftSymbol and uriBase. */ constructor() public { supportedInterfaces[0x80ac58cd] = true; // ERC721 supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable } /** * @dev Transfers the ownership of an NFT from one address to another address. * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this * function checks if `_to` is a smart contract (code size > 0). If so, it calls * `onERC721Received` on `_to` and throws if the return value is not * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. * @param _from The current owner of the NFT. * @param _to The new owner. * @param _tokenId The NFT to transfer. * @param _data Additional data with no specified format, sent in call to `_to`. */ function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes calldata _data ) external { _safeTransferFrom(_from, _to, _tokenId, _data); } /** * @dev Transfers the ownership of an NFT from one address to another address. * @notice This works identically to the other function with an extra data parameter, except this * function just sets data to "". * @param _from The current owner of the NFT. * @param _to The new owner. * @param _tokenId The NFT to transfer. */ function safeTransferFrom( address _from, address _to, uint256 _tokenId ) external { _safeTransferFrom(_from, _to, _tokenId, ""); } /** * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero * address. Throws if `_tokenId` is not a valid NFT. * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else * they maybe be permanently lost. * @param _from The current owner of the NFT. * @param _to The new owner. * @param _tokenId The NFT to transfer. */ function transferFrom( address _from, address _to, uint256 _tokenId ) external { _transferFrom(_from, _to, _tokenId); } /** * @dev Set or reaffirm the approved address for an NFT. * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is * the current NFT owner, or an authorized operator of the current owner. * @param _approved Address to be approved for the given NFT ID. * @param _tokenId ID of the token to be approved. */ function approve( address _approved, uint256 _tokenId ) external { // can operate address tokenOwner = idToOwner[_tokenId]; require( tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender], NOT_OWNER_OR_OPERATOR ); idToApproval[_tokenId] = _approved; emit Approval(tokenOwner, _approved, _tokenId); } /** * @dev Enables or disables approval for a third party ("operator") to manage all of * `msg.sender`'s assets. It also emits the ApprovalForAll event. * @notice This works even if sender doesn't own any tokens at the time. * @param _operator Address to add to the set of authorized operators. * @param _approved True if the operators is approved, false to revoke approval. */ function setApprovalForAll( address _operator, bool _approved ) external { ownerToOperators[msg.sender][_operator] = _approved; emit ApprovalForAll(msg.sender, _operator, _approved); } /** * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are * considered invalid, and this function throws for queries about the zero address. * @param _owner Address for whom to query the balance. * @return Balance of _owner. */ function balanceOf( address _owner ) external view returns (uint256) { require(_owner != address(0), ZERO_ADDRESS); return ownerToIds[_owner].length; } /** * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered * invalid, and queries about them do throw. * @param _tokenId The identifier for an NFT. * @return Address of _tokenId owner. */ function ownerOf( uint256 _tokenId ) external view returns (address _owner) { _owner = idToOwner[_tokenId]; require(_owner != address(0), NOT_VALID_NFT); } /** * @dev Get the approved address for a single NFT. * @notice Throws if `_tokenId` is not a valid NFT. * @param _tokenId ID of the NFT to query the approval of. * @return Address that _tokenId is approved for. */ function getApproved( uint256 _tokenId ) external view returns (address) { require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); return idToApproval[_tokenId]; } /** * @dev Checks if `_operator` is an approved operator for `_owner`. * @param _owner The address that owns the NFTs. * @param _operator The address that acts on behalf of the owner. * @return True if approved for all, false otherwise. */ function isApprovedForAll( address _owner, address _operator ) external view returns (bool) { return ownerToOperators[_owner][_operator]; } /** * @dev Returns the count of all existing NFTs. * @return Total supply of NFTs. */ function totalSupply() external view returns (uint256) { return tokens.length; } /** * @dev Returns NFT ID by its index. * @param _index A counter less than `totalSupply()`. * @return Token id. */ function tokenByIndex( uint256 _index ) external view returns (uint256) { require(_index < tokens.length, INVALID_INDEX); return tokens[_index]; } /** * @dev returns the n-th NFT ID from a list of owner's tokens. * @param _owner Token owner's address. * @param _index Index number representing n-th token in owner's list of tokens. * @return Token id. */ function tokenOfOwnerByIndex( address _owner, uint256 _index ) external view returns (uint256) { require(_index < ownerToIds[_owner].length, INVALID_INDEX); return ownerToIds[_owner][_index]; } /** * @dev Returns a descriptive name for a collection of NFTs. * @return Representing name. */ function name() external view returns (string memory _name) { _name = nftName; } /** * @dev Returns an abbreviated name for NFTs. * @return Representing symbol. */ function symbol() external view returns (string memory _symbol) { _symbol = nftSymbol; } /** * @notice A distinct Uniform Resource Identifier (URI) for a given asset. * @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC 3986. The URI may point * to a JSON file that conforms to the "ERC721 Metadata JSON Schema". * @param _tokenId Id for which we want URI. * @return URI of _tokenId. */ function tokenURI( uint256 _tokenId ) external view returns (string memory) { require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); if (bytes(uriBase).length > 0) { return string(abi.encodePacked(uriBase, _uint2str(_tokenId))); } return ""; } /** * @dev Set a distinct URI (RFC 3986) base for all nfts. * @notice this is a internal function which should be called from user-implemented external * function. Its purpose is to show and properly initialize data structures when using this * implementation. * @param _uriBase String representing RFC 3986 URI base. */ function _setUriBase( string memory _uriBase ) internal { uriBase = _uriBase; } /** * @dev Creates a new NFT. * @notice This is a private function which should be called from user-implemented external * function. Its purpose is to show and properly initialize data structures when using this * implementation. * @param _to The address that will own the created NFT. * @param _tokenId of the NFT to be created by the msg.sender. */ function _create( address _to, uint256 _tokenId ) internal { require(_to != address(0), ZERO_ADDRESS); require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS); // add NFT idToOwner[_tokenId] = _to; uint256 length = ownerToIds[_to].push(_tokenId); idToOwnerIndex[_tokenId] = length - 1; // add to tokens array length = tokens.push(_tokenId); idToIndex[_tokenId] = length - 1; emit Transfer(address(0), _to, _tokenId); } /** * @dev Destroys a NFT. * @notice This is a private function which should be called from user-implemented external * destroy function. Its purpose is to show and properly initialize data structures when using this * implementation. * @param _tokenId ID of the NFT to be destroyed. */ function _destroy( uint256 _tokenId ) internal { // valid NFT address _owner = idToOwner[_tokenId]; require(_owner != address(0), NOT_VALID_NFT); // clear approval if (idToApproval[_tokenId] != address(0)) { delete idToApproval[_tokenId]; } // remove NFT assert(ownerToIds[_owner].length > 0); uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId]; uint256 lastTokenIndex = ownerToIds[_owner].length - 1; uint256 lastToken; if (lastTokenIndex != tokenToRemoveIndex) { lastToken = ownerToIds[_owner][lastTokenIndex]; ownerToIds[_owner][tokenToRemoveIndex] = lastToken; idToOwnerIndex[lastToken] = tokenToRemoveIndex; } delete idToOwner[_tokenId]; delete idToOwnerIndex[_tokenId]; ownerToIds[_owner].length--; // remove from tokens array assert(tokens.length > 0); uint256 tokenIndex = idToIndex[_tokenId]; lastTokenIndex = tokens.length - 1; lastToken = tokens[lastTokenIndex]; tokens[tokenIndex] = lastToken; tokens.length--; // Consider adding a conditional check for the last token in order to save GAS. idToIndex[lastToken] = tokenIndex; idToIndex[_tokenId] = 0; emit Transfer(_owner, address(0), _tokenId); } /** * @dev Helper methods that actually does the transfer. * @param _from The current owner of the NFT. * @param _to The new owner. * @param _tokenId The NFT to transfer. */ function _transferFrom( address _from, address _to, uint256 _tokenId ) internal { // valid NFT require(_from != address(0), ZERO_ADDRESS); require(idToOwner[_tokenId] == _from, NOT_VALID_NFT); require(_to != address(0), ZERO_ADDRESS); // can transfer require( _from == msg.sender || idToApproval[_tokenId] == msg.sender || ownerToOperators[_from][msg.sender], NOT_OWNER_APPROWED_OR_OPERATOR ); // clear approval if (idToApproval[_tokenId] != address(0)) { delete idToApproval[_tokenId]; } // remove NFT assert(ownerToIds[_from].length > 0); uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId]; uint256 lastTokenIndex = ownerToIds[_from].length - 1; if (lastTokenIndex != tokenToRemoveIndex) { uint256 lastToken = ownerToIds[_from][lastTokenIndex]; ownerToIds[_from][tokenToRemoveIndex] = lastToken; idToOwnerIndex[lastToken] = tokenToRemoveIndex; } ownerToIds[_from].length--; // add NFT idToOwner[_tokenId] = _to; uint256 length = ownerToIds[_to].push(_tokenId); idToOwnerIndex[_tokenId] = length - 1; emit Transfer(_from, _to, _tokenId); } /** * @dev Helper function that actually does the safeTransfer. * @param _from The current owner of the NFT. * @param _to The new owner. * @param _tokenId The NFT to transfer. * @param _data Additional data with no specified format, sent in call to `_to`. */ function _safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes memory _data ) internal { if (_to.isContract()) { require( ERC721TokenReceiver(_to) .onERC721Received(msg.sender, _from, _tokenId, _data) == MAGIC_ON_ERC721_RECEIVED, NOT_ABLE_TO_RECEIVE_NFT ); } _transferFrom(_from, _to, _tokenId); } /** * @dev Helper function that changes uint to string representation. * @return String representation. */ function _uint2str( uint256 _i ) internal pure returns (string memory str) { if (_i == 0) { return "0"; } uint256 j = _i; uint256 length; while (j != 0) { length++; j /= 10; } bytes memory bstr = new bytes(length); uint256 k = length - 1; j = _i; while (j != 0) { bstr[k--] = byte(uint8(48 + j % 10)); j /= 10; } str = string(bstr); } } // File: contracts/ArianeeSmartAsset.sol pragma solidity 0.5.6; contract ArianeeWhitelist { function addWhitelistedAddress(uint256 _tokenId, address _address) external; } contract ArianeeStore{ function canTransfer(address _to,address _from,uint256 _tokenId) external returns(bool); function canDestroy(uint256 _tokenId, address _sender) external returns(bool); } /// @title Contract handling Arianee Certificates. contract ArianeeSmartAsset is NFTokenMetadataEnumerable, Abilitable, Ownable, Pausable { /** * @dev Mapping from token id to URI. */ mapping(uint256 => string) internal idToUri; /** * @dev Mapping from token id to Token Access (0=view, 1=transfer). */ mapping(uint256 => mapping(uint256 => address)) internal tokenAccess; /** * @dev Mapping from token id to TokenImprintUpdate. */ mapping(uint256 => bytes32) internal idToImprint; /** * @dev Mapping from token id to recovery request bool. */ mapping(uint256=>bool) internal recoveryRequest; /** * @dev Mapping from token id to total rewards for this NFT. */ mapping(uint256=>uint256) internal rewards; /** * @dev Mapping from token id to Cert. */ mapping(uint256 => Cert) internal certificate; /** * @dev This emits when a new address is set. */ event SetAddress(string _addressType, address _newAddress); struct Cert { address tokenIssuer; uint256 tokenCreationDate; uint256 tokenRecoveryTimestamp; } /** * @dev Ability to create and hydrate NFT. */ uint8 constant ABILITY_CREATE_ASSET = 2; /** * @dev Error constants. */ string constant CAPABILITY_NOT_SUPPORTED = "007001"; string constant TRANSFERS_DISABLED = "007002"; string constant NOT_VALID_CERT = "007003"; string constant NFT_ALREADY_SET = "007006"; string constant NOT_OPERATOR = "007004"; /** * Interface for all the connected contracts. */ ArianeeWhitelist public arianeeWhitelist; ArianeeStore public store; /** * @dev This emits when a token is hydrated. */ event Hydrated(uint256 _tokenId, bytes32 _imprint, string _uri, address _initialKey, uint256 _tokenRecoveryTimestamp, bool _initialKeyIsRequestKey, uint256 _tokenCreation); /** * @dev This emits when a issuer request a NFT recovery. */ event RecoveryRequestUpdated(uint256 _tokenId, bool _active); /** * @dev This emits when a NFT is recovered to the issuer. */ event TokenRecovered(uint256 _token); /** * @dev This emits when a NFT's URI is udpated. */ event TokenURIUpdated(uint256 _tokenId, string URI); /** * @dev This emits when a token access is added. */ event TokenAccessAdded(uint256 _tokenId, address _encryptedTokenKey, bool _enable, uint256 _tokenType); /** * @dev This emits when a token access is destroyed. */ event TokenDestroyed(uint256 _tokenId); /** * @dev This emits when the uri base is udpated. */ event SetNewUriBase(string _newUriBase); /** * @dev Check if the msg.sender can operate the NFT. * @param _tokenId ID of the NFT to test. * @param _operator Address to test. */ modifier isOperator(uint256 _tokenId, address _operator) { require(canOperate(_tokenId, _operator), NOT_OPERATOR); _; } /** * @dev Check if msg.sender is the issuer of a NFT. * @param _tokenId ID of the NFT to test. */ modifier isIssuer(uint256 _tokenId) { require(msg.sender == certificate[_tokenId].tokenIssuer); _; } /** * @dev Initialize this contract. Acts as a constructor * @param _arianeeWhitelistAddress Adress of the whitelist contract. */ constructor( address _arianeeWhitelistAddress ) public { nftName = "Arianee Smart-Asset"; nftSymbol = "AriaSA"; setWhitelistAddress(_arianeeWhitelistAddress); _setUriBase("https://cert.arianee.org/"); } /** * @notice Change address of the store infrastructure. * @param _storeAddress new address of the store. */ function setStoreAddress(address _storeAddress) external onlyOwner(){ store = ArianeeStore(address(_storeAddress)); emit SetAddress("storeAddress", _storeAddress); } /** * @notice Reserve a NFT at the given ID. * @dev Has to be called through an authorized contract. * @dev Can only be called by an authorized address. * @param _tokenId ID to reserve. * @param _to receiver of the token. * @param _rewards total rewards of this NFT. */ function reserveToken(uint256 _tokenId, address _to, uint256 _rewards) external hasAbilities(ABILITY_CREATE_ASSET) whenNotPaused() { super._create(_to, _tokenId); rewards[_tokenId] = _rewards; } /** * @notice Recover the NFT to the issuer. * @dev only if called by the issuer and if called before the token Recovery Timestamp of the NFT. * @param _tokenId ID of the NFT to recover. */ function recoverTokenToIssuer(uint256 _tokenId) external whenNotPaused() isIssuer(_tokenId) { require(block.timestamp < certificate[_tokenId].tokenRecoveryTimestamp); idToApproval[_tokenId] = certificate[_tokenId].tokenIssuer; _transferFrom(idToOwner[_tokenId], certificate[_tokenId].tokenIssuer, _tokenId); emit TokenRecovered(_tokenId); } /** * @notice Update a recovery request (doesn't transfer the NFT). * @dev Works only if called by the issuer. * @param _tokenId ID of the NFT to recover. * @param _active boolean to active or unactive the request. */ function updateRecoveryRequest(uint256 _tokenId, bool _active) external whenNotPaused() isIssuer(_tokenId){ recoveryRequest[_tokenId] = _active; emit RecoveryRequestUpdated(_tokenId, _active); } /** * @notice Valid a recovery request and transfer the NFT to the issuer. * @dev only if the request is active and if called by the owner of the contract. * @param _tokenId Id of the NFT to recover. */ function validRecoveryRequest(uint256 _tokenId) external onlyOwner(){ require(recoveryRequest[_tokenId]); recoveryRequest[_tokenId] = false; idToApproval[_tokenId] = owner; _transferFrom(idToOwner[_tokenId], certificate[_tokenId].tokenIssuer, _tokenId); emit RecoveryRequestUpdated(_tokenId, false); emit TokenRecovered(_tokenId); } /** * @notice External function to update the tokenURI. * @notice Can only be called by the NFT's issuer. * @param _tokenId ID of the NFT to edit. * @param _uri New URI for the certificate. */ function updateTokenURI(uint256 _tokenId, string calldata _uri) external isIssuer(_tokenId) whenNotPaused() { require(idToOwner[_tokenId] != address(0), NOT_VALID_CERT); idToUri[_tokenId] = _uri; emit TokenURIUpdated(_tokenId, _uri); } /** * @notice Add a token access to a NFT. * @notice can only be called by an NFT's operator. * @param _tokenId ID of the NFT. * @param _key Public address of the token to encode the hash with. * @param _enable Enable or disable the token access. * @param _tokenType Type of token access (0=view, 1=tranfer). * @return true. */ function addTokenAccess(uint256 _tokenId, address _key, bool _enable, uint256 _tokenType) external isOperator(_tokenId, msg.sender) whenNotPaused() { require(_tokenType>0); if (_enable) { tokenAccess[_tokenId][_tokenType] = _key; } else { tokenAccess[_tokenId][_tokenType] = address(0); } emit TokenAccessAdded(_tokenId, _key, _enable, _tokenType); } /** * @notice Transfers the ownership of a NFT to another address * @notice Requires to send the correct tokenKey and the NFT has to be requestable * @dev Has to be called through an authorized contract. * @dev approve the requester if _tokenKey is valid to allow transferFrom without removing ERC721 compliance. * @param _tokenId ID of the NFT to transfer. * @param _hash Hash of tokenId + newOwner address. * @param _keepRequestToken If false erase the access token of the NFT. * @param _newOwner Address of the new owner of the NFT. * @return total rewards of this NFT. */ function requestToken(uint256 _tokenId, bytes32 _hash, bool _keepRequestToken, address _newOwner, bytes calldata _signature) external hasAbilities(ABILITY_CREATE_ASSET) whenNotPaused() returns(uint256 reward){ require(isTokenValid(_tokenId, _hash, 1, _signature)); bytes32 message = keccak256(abi.encode(_tokenId, _newOwner)); require(ECDSA.toEthSignedMessageHash(message) == _hash); idToApproval[_tokenId] = msg.sender; if(!_keepRequestToken){ tokenAccess[_tokenId][1] = address(0); } _transferFrom(idToOwner[_tokenId], _newOwner, _tokenId); reward = rewards[_tokenId]; delete rewards[_tokenId]; } /** * @notice Destroy a token. * @notice Can only be called by the issuer. * @param _tokenId to destroy. */ function destroy(uint256 _tokenId) external whenNotPaused() { require(store.canDestroy(_tokenId, msg.sender)); _destroy(_tokenId); idToImprint[_tokenId] = ""; idToUri[_tokenId] = ""; tokenAccess[_tokenId][0] = address(0); tokenAccess[_tokenId][1] = address(0); rewards[_tokenId] = 0; Cert memory _emptyCert = Cert({ tokenIssuer : address(0), tokenCreationDate: 0, tokenRecoveryTimestamp: 0 }); certificate[_tokenId] = _emptyCert; emit TokenDestroyed(_tokenId); } /** * @notice return the URI of a NFT. * @param _tokenId uint256 ID of the NFT. * @return URI of the NFT. */ function tokenURI(uint256 _tokenId) external view returns (string memory){ require(idToOwner[_tokenId] != address(0), NOT_VALID_CERT); if(bytes(idToUri[_tokenId]).length > 0){ return idToUri[_tokenId]; } else{ return string(abi.encodePacked(uriBase, _uint2str(_tokenId))); } } /** * @notice Check if a token is requestable. * @param _tokenId uint256 ID of the token to check. * @return True if the NFT is requestable. */ function isRequestable(uint256 _tokenId) external view returns (bool) { return tokenAccess[_tokenId][1] != address(0); } /** * @notice The issuer address for a given Token ID. * @dev Throws if `_tokenId` is not a valid NFT. * @param _tokenId Id for which we want the issuer. * @return Issuer address of _tokenId. */ function issuerOf(uint256 _tokenId) external view returns(address _tokenIssuer){ require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); _tokenIssuer = certificate[_tokenId].tokenIssuer; } /** * @notice The imprint for a given Token ID. * @dev Throws if `_tokenId` is not a valid NFT. * @param _tokenId Id for which we want the imprint. * @return Imprint address of _tokenId. */ function tokenImprint(uint256 _tokenId) external view returns(bytes32 _imprint){ require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); _imprint = idToImprint[_tokenId]; } /** * @notice The creation date for a given Token ID. * @dev Throws if `_tokenId` is not a valid NFT. * @param _tokenId Id for which we want the creation date. * @return Creation date of _tokenId. */ function tokenCreation(uint256 _tokenId) external view returns(uint256 _tokenCreation){ require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); _tokenCreation = certificate[_tokenId].tokenCreationDate; } /** * @notice The Token Access for a given Token ID and token type. * @dev Throws if `_tokenId` is not a valid NFT. * @param _tokenId Id for which we want the token access. * @param _tokenType for which we want the token access. * @return Token access of _tokenId. */ function tokenHashedAccess(uint256 _tokenId, uint256 _tokenType) external view returns(address _tokenAccess){ require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); _tokenAccess = tokenAccess[_tokenId][_tokenType]; } /** * @notice The recovery timestamp for a given Token ID. * @dev Throws if `_tokenId` is not a valid NFT. * @param _tokenId Id for which we want the recovery timestamp. * @return Recovery timestamp of _tokenId. */ function tokenRecoveryDate(uint256 _tokenId) external view returns(uint256 _tokenRecoveryTimestamp){ require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); _tokenRecoveryTimestamp = certificate[_tokenId].tokenRecoveryTimestamp; } /** * @notice The recovery timestamp for a given Token ID. * @dev Throws if `_tokenId` is not a valid NFT. * @param _tokenId Id for which we want the recovery timestamp. * @return Recovery timestamp of _tokenId. */ function recoveryRequestOpen(uint256 _tokenId) external view returns(bool _recoveryRequest){ require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); _recoveryRequest = recoveryRequest[_tokenId]; } /** * @notice The rewards for a given Token ID. * @param _tokenId Id for which we want the rewards. * @return Rewards of _tokenId. */ function getRewards(uint256 _tokenId) external view returns(uint256){ return rewards[_tokenId]; } /** * @notice Check if an operator is valid for a given NFT. * @param _tokenId nft to check. * @param _operator operator to check. * @return true if operator is valid. */ function canOperate(uint256 _tokenId, address _operator) public view returns (bool){ address tokenOwner = idToOwner[_tokenId]; return tokenOwner == _operator || ownerToOperators[tokenOwner][_operator]; } /** * @notice Change the base URI address. * @param _newURIBase the new URI base address. */ function setUriBase(string memory _newURIBase) public onlyOwner(){ _setUriBase(_newURIBase); emit SetNewUriBase(_newURIBase); } /** * @notice Change address of the whitelist. * @param _whitelistAddres new address of the whitelist. */ function setWhitelistAddress(address _whitelistAddres) public onlyOwner(){ arianeeWhitelist = ArianeeWhitelist(address(_whitelistAddres)); emit SetAddress("whitelistAddress", _whitelistAddres); } /** * @notice Specify information on a reserved NFT. * @dev to be called through an authorized contract. * @dev Can only be called once and by an NFT's operator. * @param _tokenId ID of the NFT to modify. * @param _imprint Proof of the certification. * @param _uri URI of the JSON certification. * @param _initialKey Initial key. * @param _tokenRecoveryTimestamp Limit date for the issuer to be able to transfer back the NFT. * @param _initialKeyIsRequestKey If true set initial key as request key. */ function hydrateToken(uint256 _tokenId, bytes32 _imprint, string memory _uri, address _initialKey, uint256 _tokenRecoveryTimestamp, bool _initialKeyIsRequestKey, address _owner) public hasAbilities(ABILITY_CREATE_ASSET) whenNotPaused() isOperator(_tokenId, _owner) returns(uint256){ require(!(certificate[_tokenId].tokenCreationDate > 0), NFT_ALREADY_SET); uint256 _tokenCreation = block.timestamp; tokenAccess[_tokenId][0] = _initialKey; idToImprint[_tokenId] = _imprint; idToUri[_tokenId] = _uri; arianeeWhitelist.addWhitelistedAddress(_tokenId, _owner); if (_initialKeyIsRequestKey) { tokenAccess[_tokenId][1] = _initialKey; } Cert memory _cert = Cert({ tokenIssuer : _owner, tokenCreationDate: _tokenCreation, tokenRecoveryTimestamp :_tokenRecoveryTimestamp }); certificate[_tokenId] = _cert; emit Hydrated(_tokenId, _imprint, _uri, _initialKey, _tokenRecoveryTimestamp, _initialKeyIsRequestKey, _tokenCreation); return rewards[_tokenId]; } /** * @notice Check if a token access is valid. * @param _tokenId ID of the NFT to validate. * @param _hash Hash of tokenId + newOwner address. * @param _tokenType Type of token access (0=view, 1=transfer). */ function isTokenValid(uint256 _tokenId, bytes32 _hash, uint256 _tokenType, bytes memory _signature) public view returns (bool){ return ECDSA.recover(_hash, _signature) == tokenAccess[_tokenId][_tokenType]; } /** * @notice Legacy function of TransferFrom, add the new owner as whitelisted for the message. * @dev Require the store to approve the transfer. */ function _transferFrom(address _to, address _from, uint256 _tokenId) internal { require(store.canTransfer(_to, _from, _tokenId)); super._transferFrom(_to, _from, _tokenId); arianeeWhitelist.addWhitelistedAddress(_tokenId, _to); } }
Contract ABI
[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"_interfaceID"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isTokenValid","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bytes32","name":"_hash"},{"type":"uint256","name":"_tokenType"},{"type":"bytes","name":"_signature"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"_name"}],"name":"name","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getApproved","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"approve","inputs":[{"type":"address","name":"_approved"},{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"grantAbilities","inputs":[{"type":"address","name":"_target"},{"type":"uint256","name":"_abilities"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"validRecoveryRequest","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"arianeeWhitelist","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalSupply","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateTokenURI","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"string","name":"_uri"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferFrom","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"reserveToken","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"address","name":"_to"},{"type":"uint256","name":"_rewards"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setUriBase","inputs":[{"type":"string","name":"_newURIBase"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"tokenOfOwnerByIndex","inputs":[{"type":"address","name":"_owner"},{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"unpause","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"addressToAbility","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"tokenByIndex","inputs":[{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"paused","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"_tokenCreation"}],"name":"tokenCreation","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"_owner"}],"name":"ownerOf","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"_recoveryRequest"}],"name":"recoveryRequestOpen","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setStoreAddress","inputs":[{"type":"address","name":"_storeAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"_imprint"}],"name":"tokenImprint","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"canOperate","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"address","name":"_operator"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"pause","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"_symbol"}],"name":"symbol","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"store","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"destroy","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setWhitelistAddress","inputs":[{"type":"address","name":"_whitelistAddres"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setApprovalForAll","inputs":[{"type":"address","name":"_operator"},{"type":"bool","name":"_approved"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"_tokenIssuer"}],"name":"issuerOf","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"revokeAbilities","inputs":[{"type":"address","name":"_target"},{"type":"uint256","name":"_abilities"},{"type":"bool","name":"_allowSuperRevoke"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"recoverTokenToIssuer","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addTokenAccess","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"address","name":"_key"},{"type":"bool","name":"_enable"},{"type":"uint256","name":"_tokenType"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"_tokenId"},{"type":"bytes","name":"_data"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isAble","inputs":[{"type":"address","name":"_target"},{"type":"uint256","name":"_abilities"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getRewards","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":""}],"name":"tokenURI","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"_tokenAccess"}],"name":"tokenHashedAccess","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"uint256","name":"_tokenType"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"_tokenRecoveryTimestamp"}],"name":"tokenRecoveryDate","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":"reward"}],"name":"requestToken","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bytes32","name":"_hash"},{"type":"bool","name":"_keepRequestToken"},{"type":"address","name":"_newOwner"},{"type":"bytes","name":"_signature"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isApprovedForAll","inputs":[{"type":"address","name":"_owner"},{"type":"address","name":"_operator"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"hydrateToken","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bytes32","name":"_imprint"},{"type":"string","name":"_uri"},{"type":"address","name":"_initialKey"},{"type":"uint256","name":"_tokenRecoveryTimestamp"},{"type":"bool","name":"_initialKeyIsRequestKey"},{"type":"address","name":"_owner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"_newOwner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateRecoveryRequest","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bool","name":"_active"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isRequestable","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":""}],"name":"uriBase","inputs":[],"constant":true},{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"address","name":"_arianeeWhitelistAddress"}]},{"type":"event","name":"SetAddress","inputs":[{"type":"string","name":"_addressType","indexed":false},{"type":"address","name":"_newAddress","indexed":false}],"anonymous":false},{"type":"event","name":"Hydrated","inputs":[{"type":"uint256","name":"_tokenId","indexed":false},{"type":"bytes32","name":"_imprint","indexed":false},{"type":"string","name":"_uri","indexed":false},{"type":"address","name":"_initialKey","indexed":false},{"type":"uint256","name":"_tokenRecoveryTimestamp","indexed":false},{"type":"bool","name":"_initialKeyIsRequestKey","indexed":false},{"type":"uint256","name":"_tokenCreation","indexed":false}],"anonymous":false},{"type":"event","name":"RecoveryRequestUpdated","inputs":[{"type":"uint256","name":"_tokenId","indexed":false},{"type":"bool","name":"_active","indexed":false}],"anonymous":false},{"type":"event","name":"TokenRecovered","inputs":[{"type":"uint256","name":"_token","indexed":false}],"anonymous":false},{"type":"event","name":"TokenURIUpdated","inputs":[{"type":"uint256","name":"_tokenId","indexed":false},{"type":"string","name":"URI","indexed":false}],"anonymous":false},{"type":"event","name":"TokenAccessAdded","inputs":[{"type":"uint256","name":"_tokenId","indexed":false},{"type":"address","name":"_encryptedTokenKey","indexed":false},{"type":"bool","name":"_enable","indexed":false},{"type":"uint256","name":"_tokenType","indexed":false}],"anonymous":false},{"type":"event","name":"TokenDestroyed","inputs":[{"type":"uint256","name":"_tokenId","indexed":false}],"anonymous":false},{"type":"event","name":"SetNewUriBase","inputs":[{"type":"string","name":"_newUriBase","indexed":false}],"anonymous":false},{"type":"event","name":"Pause","inputs":[],"anonymous":false},{"type":"event","name":"Unpause","inputs":[],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false},{"type":"event","name":"GrantAbilities","inputs":[{"type":"address","name":"_target","indexed":true},{"type":"uint256","name":"_abilities","indexed":true}],"anonymous":false},{"type":"event","name":"RevokeAbilities","inputs":[{"type":"address","name":"_target","indexed":true},{"type":"uint256","name":"_abilities","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"_from","indexed":true},{"type":"address","name":"_to","indexed":true},{"type":"uint256","name":"_tokenId","indexed":true}],"anonymous":false},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"_owner","indexed":true},{"type":"address","name":"_approved","indexed":true},{"type":"uint256","name":"_tokenId","indexed":true}],"anonymous":false},{"type":"event","name":"ApprovalForAll","inputs":[{"type":"address","name":"_owner","indexed":true},{"type":"address","name":"_operator","indexed":true},{"type":"bool","name":"_approved","indexed":false}],"anonymous":false}]
Contract Creation Code
0x6080604052600c805460a060020a60ff02191690553480156200002157600080fd5b5060405160208062004503833981018060405260208110156200004357600080fd5b50517f67be87c3ff9960ca1e9cfac5cab2ff4747269cf9ed20c9b7306235ac35a491c58054600160ff1991821681179092557ff7815fccbf112960a73756e185887fedcb9fc64ca0a16cc5923b7960ed78080080548216831790557f9562381dfbc2d8b8b66e765249f330164b73e329e5f01670660643571d1974df80548216831790557f77b7bbe0e49b76487c9476b5db3354cf5270619d0037ccb899c2a4c4a75b4318805490911682179055336000818152600b6020526040808220849055517fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f9190a3600c8054600160a060020a031916331790556040805180820190915260138082527f417269616e656520536d6172742d41737365740000000000000000000000000060209092019182526200018191600191620003be565b506040805180820190915260068082527f41726961534100000000000000000000000000000000000000000000000000006020909201918252620001c891600291620003be565b50620001dd8164010000000062000233810204565b6200022c6040518060400160405280601981526020017f68747470733a2f2f636572742e617269616e65652e6f72672f00000000000000815250620003a5640100000000026401000000009004565b5062000463565b600c5460408051808201909152600681527f3031383030310000000000000000000000000000000000000000000000000000602082015290600160a060020a031633146200031c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620002e0578181015183820152602001620002c6565b50505050905090810190601f1680156200030e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060138054600160a060020a038316600160a060020a031990911681179091556040805160208101929092528082526010828201527f77686974656c69737441646472657373000000000000000000000000000000006060830152517fb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb965119181900360800190a150565b8051620003ba906003906020840190620003be565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200040157805160ff191683800117855562000431565b8280016001018555821562000431579182015b828111156200043157825182559160200191906001019062000414565b506200043f92915062000443565b5090565b6200046091905b808211156200043f57600081556001016200044a565b90565b61409080620004736000396000f3fe608060405234801561001057600080fd5b50600436106102495760e060020a600035046301ffc9a7811461024e5780630657a5ea1461028957806306fdde0314610340578063081812fc146103bd578063095ea7b3146103f65780630ab319e8146104245780631332f1b814610450578063165ec2e21461046d57806318160ddd1461047557806318e97fd11461048f57806323b872dd146105045780632526c9331461053a57806327fc0cff1461056c5780632f745c59146106105780633f4ba83a1461063c57806342842e0e1461064457806345a32c861461067a5780634f6ccce7146106a05780635c975abb146106bd5780635facb882146106c55780636352211e146106e257806363ad2b6a146106ff5780636559e59a1461071c57806370a082311461074257806370c31afc1461076857806380a4edda146107855780638456cb59146107b15780638da5cb5b146107b957806395d89b41146107c1578063975057e7146107c95780639d118770146107d1578063a224c745146107ee578063a22cb46514610814578063a4e2ee1114610842578063aca910e71461085f578063b5aaa9d514610893578063b71c34d5146108b0578063b88d4fde146108ea578063ba00a33014610978578063c0d8012c146109a4578063c87b56dd146109c1578063cc55578e146109de578063dde5c1c714610a01578063e261ed7714610a1e578063e985e9c514610aaf578063ec046d0a14610add578063f2fde38b14610bac578063f3fd860514610bd2578063f421b0e914610bf7578063fbca0ce114610c14575b600080fd5b6102756004803603602081101561026457600080fd5b5035600160e060020a031916610c1c565b604080519115158252519081900360200190f35b6102756004803603608081101561029f57600080fd5b81359160208101359160408201359190810190608081016060820135602060020a8111156102cc57600080fd5b8201836020820111156102de57600080fd5b803590602001918460018302840111602060020a831117156102ff57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610c3f945050505050565b610348610c7f565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561038257818101518382015260200161036a565b50505050905090810190601f1680156103af5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103da600480360360208110156103d357600080fd5b5035610d14565b60408051600160a060020a039092168252519081900360200190f35b6104226004803603604081101561040c57600080fd5b50600160a060020a038135169060200135610df8565b005b6104226004803603604081101561043a57600080fd5b50600160a060020a038135169060200135610f0f565b6104226004803603602081101561046657600080fd5b5035610fff565b6103da611141565b61047d611150565b60408051918252519081900360200190f35b610422600480360360408110156104a557600080fd5b81359190810190604081016020820135602060020a8111156104c657600080fd5b8201836020820111156104d857600080fd5b803590602001918460018302840111602060020a831117156104f957600080fd5b509092509050611157565b6104226004803603606081101561051a57600080fd5b50600160a060020a038135811691602081013590911690604001356112a6565b6104226004803603606081101561055057600080fd5b50803590600160a060020a0360208201351690604001356112b6565b6104226004803603602081101561058257600080fd5b810190602081018135602060020a81111561059c57600080fd5b8201836020820111156105ae57600080fd5b803590602001918460018302840111602060020a831117156105cf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611393945050505050565b61047d6004803603604081101561062657600080fd5b50600160a060020a0381351690602001356114b6565b61042261157b565b6104226004803603606081101561065a57600080fd5b50600160a060020a0381358116916020810135909116906040013561164a565b61047d6004803603602081101561069057600080fd5b5035600160a060020a0316611665565b61047d600480360360208110156106b657600080fd5b5035611677565b61027561170d565b61047d600480360360208110156106db57600080fd5b503561171d565b6103da600480360360208110156106f857600080fd5b50356117be565b6102756004803603602081101561071557600080fd5b5035611850565b6104226004803603602081101561073257600080fd5b5035600160a060020a03166118f1565b61047d6004803603602081101561075857600080fd5b5035600160a060020a03166119d7565b61047d6004803603602081101561077e57600080fd5b5035611a6f565b6102756004803603604081101561079b57600080fd5b5080359060200135600160a060020a0316611b0d565b610422611b64565b6103da611c3a565b610348611c49565b6103da611ca7565b610422600480360360208110156107e757600080fd5b5035611cb6565b6104226004803603602081101561080457600080fd5b5035600160a060020a0316611e73565b6104226004803603604081101561082a57600080fd5b50600160a060020a0381351690602001351515611f5d565b6103da6004803603602081101561085857600080fd5b5035611fcb565b6104226004803603606081101561087557600080fd5b50600160a060020a0381351690602081013590604001351515612072565b610422600480360360208110156108a957600080fd5b50356121f4565b610422600480360360808110156108c657600080fd5b50803590600160a060020a03602082013516906040810135151590606001356122c4565b6104226004803603608081101561090057600080fd5b600160a060020a03823581169260208101359091169160408201359190810190608081016060820135602060020a81111561093a57600080fd5b82018360208201111561094c57600080fd5b803590602001918460018302840111602060020a8311171561096d57600080fd5b509092509050612423565b6102756004803603604081101561098e57600080fd5b50600160a060020a03813516906020013561246c565b61047d600480360360208110156109ba57600080fd5b5035612505565b610348600480360360208110156109d757600080fd5b5035612517565b6103da600480360360408110156109f457600080fd5b508035906020013561273d565b61047d60048036036020811015610a1757600080fd5b50356127ef565b61047d600480360360a0811015610a3457600080fd5b8135916020810135916040820135151591600160a060020a036060820135169181019060a081016080820135602060020a811115610a7157600080fd5b820183602082011115610a8357600080fd5b803590602001918460018302840111602060020a83111715610aa457600080fd5b509092509050612890565b61027560048036036040811015610ac557600080fd5b50600160a060020a0381358116916020013516612a6a565b61047d600480360360e0811015610af357600080fd5b813591602081013591810190606081016040820135602060020a811115610b1957600080fd5b820183602082011115610b2b57600080fd5b803590602001918460018302840111602060020a83111715610b4c57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050600160a060020a0383358116945060208401359360408101351515935060600135169050612a98565b61042260048036036020811015610bc257600080fd5b5035600160a060020a0316612ee1565b61042260048036036040811015610be857600080fd5b50803590602001351515613034565b61027560048036036020811015610c0d57600080fd5b50356130ba565b6103486130e3565b600160e060020a0319811660009081526020819052604090205460ff165b919050565b6000848152600e60209081526040808320858452909152812054600160a060020a0316610c6c8584613171565b600160a060020a03161495945050505050565b60018054604080516020601f60026000196101008789161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b820191906000526020600020905b815481529060010190602001808311610ced57829003601f168201915b5050505050905090565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316610ddb5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610da0578181015183820152602001610d88565b50505050905090810190601f168015610dcd5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050600090815260096020526040902054600160a060020a031690565b600081815260086020526040902054600160a060020a031633811480610e415750600160a060020a0381166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d060020a653030363030330281525090610eb25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000828152600960205260408082208054600160a060020a031916600160a060020a0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a6530313730303102918301919091526001919082168214610fb35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a0383166000818152600b6020526040808220805486179055518492917fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f91a3505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461107c5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008181526010602052604090205460ff1661109857600080fd5b6000818152601060209081526040808320805460ff19169055600c54600983528184208054600160a060020a031916600160a060020a03928316179055600883528184205460129093529220546110f492918216911683613255565b60408051828152600060208201528151600080516020614005833981519152929181900390910190a16040805182815290516000805160206140258339815191529181900360200190a150565b601354600160a060020a031681565b6004545b90565b6000838152601260205260409020548390600160a060020a0316331461117c57600080fd5b600c5460a060020a900460ff161561119357600080fd5b6000848152600860209081526040918290205482518084019093526006835260d060020a653030373030330291830191909152600160a060020a031661121d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000848152600d60205260409020611237908484613e94565b507f931f495b9a8e5d8e61946ea5d61e021f636cfe213a801f97589c18c152e408bd84848460405180848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a150505050565b6112b1838383613255565b505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a653031373030310291830191909152600291908216821461135a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561137257600080fd5b61137c838561336b565b506000928352601160205260409092209190915550565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146114105760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5061141a8161351e565b7f2f1172752b4c027870f0c890ad9d16d3a4d3af09c120988bd8620ef750b124aa816040518080602001828103825283818151815260200191508051906020019080838360005b83811015611479578181015183820152602001611461565b50505050905090810190601f1680156114a65780820380516001836020036101000a031916815260200191505b509250505060405180910390a150565b600160a060020a038216600090815260066020818152604080842054815180830190925292815260d060020a6530303630303702918101919091529083106115425760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a038316600090815260066020526040902080548390811061156757fe5b906000526020600020015490505b92915050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146115f85760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1661160f57600080fd5b600c805460a060020a60ff02191690556040517f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3390600090a1565b6112b183838360405180602001604052806000815250613535565b600b6020526000908152604090205481565b600454604080518082019091526006815260d060020a6530303630303702602082015260009183106116ed5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600482815481106116fb57fe5b90600052602060002001549050919050565b600c5460a060020a900460ff1681565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166117a75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526012602052604090206001015490565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a0316908161184a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50919050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166118da5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526010602052604090205460ff1690565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461196e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060148054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252600c8282015260a060020a6b73746f72654164647265737302606083015251600080516020613fe58339815191529181900360800190a150565b604080518082019091526006815260d060020a65303036303031026020820152600090600160a060020a038316611a525760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600160a060020a031660009081526006602052604090205490565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316611af95760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50506000908152600f602052604090205490565b600082815260086020526040812054600160a060020a03908116908316811480611b5c5750600160a060020a038082166000908152600a602090815260408083209387168352929052205460ff165b949350505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611be15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1615611bf957600080fd5b600c805460a060020a60ff02191660a060020a1790556040517f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62590600090a1565b600c54600160a060020a031681565b60028054604080516020601f6000196101006001871615020190941685900493840181900481028201810190925282815260609390929091830182828015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b601454600160a060020a031681565b600c5460a060020a900460ff1615611ccd57600080fd5b6014546040805160e060020a6382300d89028152600481018490523360248201529051600160a060020a03909216916382300d89916044808201926020929091908290030181600087803b158015611d2457600080fd5b505af1158015611d38573d6000803e3d6000fd5b505050506040513d6020811015611d4e57600080fd5b5051611d5957600080fd5b611d62816136d4565b6000818152600f602090815260408083208390558051808301808352848252858552600d90935292209151611d98929190613f12565b506000818152600e6020908152604080832083805282528083208054600160a060020a031990811690915560018452818420805490911690558383526011909152812055611de4613f80565b506040805160608101825260008082526020808301828152838501838152868452601283529285902084518154600160a060020a031916600160a060020a039091161781559051600182015591516002909201919091558251848152925191927fbc3b3ac51ba6ff17c341408a0d6270952ecdd0bbbd47586aecc338d73af9d78d929081900390910190a15050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611ef05760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060138054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252601082820152608060020a6f77686974656c6973744164647265737302606083015251600080516020613fe58339815191529181900360800190a150565b336000818152600a60209081526040808320600160a060020a03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166120555760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600090815260126020526040902054600160a060020a031690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a65303137303031029183019190915260019190821682146121165760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b508115801561212d575033600160a060020a038516145b156121a757604080518082019091526006815260d160020a6518189b98181902602082015260018416156121a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505b600160a060020a0384166000818152600b602052604080822080548719169055518592917fbb71944f65b9a48cc7d835179fb5e874f29b60aa0195785fb54968d8dddef08a91a350505050565b600c5460a060020a900460ff161561220b57600080fd5b6000818152601260205260409020548190600160a060020a0316331461223057600080fd5b600082815260126020526040902060020154421061224d57600080fd5b60008281526012602081815260408084208054600984528286208054600160a060020a031916600160a060020a0392831617905560088452919094205492909152915461229f92918216911684613255565b6040805183815290516000805160206140258339815191529181900360200190a15050565b83336122d08282611b0d565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d02815250906123415760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561235957600080fd5b6000831161236657600080fd5b83156123a3576000868152600e6020908152604080832086845290915290208054600160a060020a031916600160a060020a0387161790556123cb565b6000868152600e6020908152604080832086845290915290208054600160a060020a03191690555b60408051878152600160a060020a0387166020820152851515818301526060810185905290517fd4fada85986a6a990ebf8397071db3525f738377b4b8d4c3e9c8847dd7c7bd409181900360800190a1505050505050565b61246585858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061353592505050565b5050505050565b600080821160405180604001604052806006815260200160d060020a6530313730303302815250906124e25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600160a060020a03919091166000908152600b602052604090205481161490565b60009081526011602052604090205490565b6000818152600860209081526040918290205482518084019093526006835260d060020a65303037303033029183019190915260609190600160a060020a03166125a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000828152600d6020526040902054600260001961010060018416150201909116041561266c576000828152600d602090815260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845290918301828280156126605780601f1061263557610100808354040283529160200191612660565b820191906000526020600020905b81548152906001019060200180831161264357829003601f168201915b50505050509050610c3a565b60036126778361396e565b60405160200180838054600181600116156101000203166002900480156126d55780601f106126b35761010080835404028352918201916126d5565b820191906000526020600020905b8154815290600101906020018083116126c1575b5050825160208401908083835b602083106127015780518252601f1990920191602091820191016126e2565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529050610c3a565b60008281526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166127c75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50506000918252600e60209081526040808420928452919052902054600160a060020a031690565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166128795760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526012602052604090206002015490565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a6530313730303102928401929092529091600291821682146129355760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561294d57600080fd5b6129908888600187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3f92505050565b61299957600080fd5b6040805160208082018b9052600160a060020a0388168284015282518083038401815260609092019092528051910120876129d382613a38565b146129dd57600080fd5b60008981526009602052604090208054600160a060020a0319163317905586612a29576000898152600e602090815260408083206001845290915290208054600160a060020a03191690555b600089815260086020526040902054612a4c90600160a060020a0316878b613255565b50505060009586525050601160205250506040822080549290555090565b600160a060020a039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a653031373030310292840192909252909160029182168214612b3d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1615612b5557600080fd5b8883612b618282611b0d565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d0281525090612bd25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008b8152601260209081526040918290206001015482518084019093526006835260d160020a6518181b98181b029183019190915215612c585760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008b8152600e6020908152604080832083805282528083208054600160a060020a031916600160a060020a038d161790558d8352600f82528083208d9055600d82529091208a514292612cb19291908d0190613f12565b506013546040805160e060020a6387159d9b028152600481018f9052600160a060020a038981166024830152915191909216916387159d9b91604480830192600092919082900301818387803b158015612d0a57600080fd5b505af1158015612d1e573d6000803e3d6000fd5b505050508615612d5c5760008c8152600e602090815260408083206001845290915290208054600160a060020a031916600160a060020a038b161790555b612d64613f80565b604051806060016040528088600160a060020a031681526020018381526020018a815250905080601260008f815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010155604082015181600201559050507f0166db8152debe7d1cfed1b1e12a32a28a986839ab44dff49682be23e29704de8d8d8d8d8d8d88604051808881526020018781526020018060200186600160a060020a0316600160a060020a0316815260200185815260200184151515158152602001838152602001828103825287818151815260200191508051906020019080838360005b83811015612e81578181015183820152602001612e69565b50505050905090810190601f168015612eae5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390a15050506000998a5250506011602052505060409095205495945050505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314612f5e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50604080518082019091526006815260d160020a6518189c181819026020820152600160a060020a038216612fd75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c8054600160a060020a031916600160a060020a0392909216919091179055565b600c5460a060020a900460ff161561304b57600080fd5b6000828152601260205260409020548290600160a060020a0316331461307057600080fd5b600083815260106020908152604091829020805460ff19168515159081179091558251868152918201528151600080516020614005833981519152929181900390910190a1505050565b6000908152600e6020908152604080832060018452909152902054600160a060020a0316151590565b6003805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156131695780601f1061313e57610100808354040283529160200191613169565b820191906000526020600020905b81548152906001019060200180831161314c57829003601f168201915b505050505081565b6000815160411461318457506000611575565b60208201516040830151606084015160001a6fa2a8918ca85bafe22016d0b997e4df6060ff60020a038211156131c05760009350505050611575565b8060ff16601b141580156131d857508060ff16601c14155b156131e95760009350505050611575565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa158015613240573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6014546040805160e160020a6372331c73028152600160a060020a0386811660048301528581166024830152604482018590529151919092169163e46638e69160648083019260209291908290030181600087803b1580156132b657600080fd5b505af11580156132ca573d6000803e3d6000fd5b505050506040513d60208110156132e057600080fd5b50516132eb57600080fd5b6132f6838383613a89565b6013546040805160e060020a6387159d9b02815260048101849052600160a060020a038681166024830152915191909216916387159d9b91604480830192600092919082900301818387803b15801561334e57600080fd5b505af1158015613362573d6000803e3d6000fd5b50505050505050565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a0383166133e35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b18181b0291830191909152600160a060020a03161561346f5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008181526008602090815260408083208054600160a060020a031916600160a060020a038716908117909155808452600683528184208054600181810183559186528486208101879055868652600785528386205560048054918201908190557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b8201879055600590945282852055905191928492600080516020614045833981519152908290a4505050565b8051613531906003906020840190613f12565b5050565b61354783600160a060020a0316613e8e565b156136c35760405160e160020a630a85bd01028082523360048301818152600160a060020a0388811660248601526044850187905260806064860190815286516084870152865194959189169463150b7a0294938b938a938a93909160a40190602085019080838360005b838110156135ca5781810151838201526020016135b2565b50505050905090810190601f1680156135f75780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561361957600080fd5b505af115801561362d573d6000803e3d6000fd5b505050506040513d602081101561364357600080fd5b5051604080518082019091526006815260d060020a6530303630303502602082015291600160e060020a0319909116146136c15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505b6136ce848484613255565b50505050565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a031690816137605760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600082815260096020526040902054600160a060020a03161561379b5760008281526009602052604090208054600160a060020a03191690555b600160a060020a0381166000908152600660205260409020546137ba57fe5b600082815260076020908152604080832054600160a060020a0385168452600690925282205490916000199091019081831461387357600160a060020a038416600090815260066020526040902080548390811061381457fe5b90600052602060002001549050806006600086600160a060020a0316600160a060020a03168152602001908152602001600020848154811061385257fe5b60009182526020808320909101929092558281526007909152604090208390555b60008581526008602090815260408083208054600160a060020a031916905560078252808320839055600160a060020a0387168352600690915290208054906138c0906000198301613faa565b506004546138ca57fe5b6000858152600560205260409020546004805460001981019450849081106138ee57fe5b90600052602060002001549150816004828154811061390957fe5b6000918252602090912001556004805490613928906000198301613faa565b5060008281526005602052604080822083905587825280822082905551879190600160a060020a03881690600080516020614045833981519152908390a4505050505050565b6060816139965750604080518082019091526001815260fc60020a6003026020820152610c3a565b8160005b81156139ae57600101600a8204915061399a565b6060816040519080825280601f01601f1916602001820160405280156139db576020820181803883390190505b50859350905060001982015b8315613a2f57600a840660300160f860020a0282828060019003935081518110613a0d57fe5b6020010190600160f860020a031916908160001a905350600a840493506139e7565b50949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038416613b015760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a03858116911614613b915760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038316613c0a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a038316331480613c385750600081815260096020526040902054600160a060020a031633145b80613c665750600160a060020a0383166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d260020a650c0c0d8c0c0d0281525090613cd75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600081815260096020526040902054600160a060020a031615613d125760008181526009602052604090208054600160a060020a03191690555b600160a060020a038316600090815260066020526040902054613d3157fe5b600081815260076020908152604080832054600160a060020a038716845260069092529091205460001901808214613de557600160a060020a0385166000908152600660205260408120805483908110613d8757fe5b90600052602060002001549050806006600088600160a060020a0316600160a060020a031681526020019081526020016000208481548110613dc557fe5b600091825260208083209091019290925591825260079052604090208290555b600160a060020a0385166000908152600660205260409020805490613e0e906000198301613faa565b5060008381526008602090815260408083208054600160a060020a031916600160a060020a038981169182179092558085526006845282852080546001810180835591875285872081018a9055898752600790955283862094909455915192938793918a16916000805160206140458339815191529190a4505050505050565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613ed55782800160ff19823516178555613f02565b82800160010185558215613f02579182015b82811115613f02578235825591602001919060010190613ee7565b50613f0e929150613fca565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613f5357805160ff1916838001178555613f02565b82800160010185558215613f02579182015b82811115613f02578251825591602001919060010190613f65565b60405180606001604052806000600160a060020a0316815260200160008152602001600081525090565b8154818355818111156112b1576000838152602090206112b19181019083015b61115491905b80821115613f0e5760008155600101613fd056feb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb9651106eb2a6b59bafdf7d5d15a5fe2681abd76406ddf85d0af873cd23c221014dc3211cd3c497c4ee51feb1ed7bbb2d072b8c18bce7bbf0cf03d310a12b4afcd9818ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820e9896e5a1e3faba7c7f12686854a548c7a25f66710bc5a5f38be182b40660cd80029000000000000000000000000d3eee7f8e8021db24825c3457d5479f2b57f40ef
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106102495760e060020a600035046301ffc9a7811461024e5780630657a5ea1461028957806306fdde0314610340578063081812fc146103bd578063095ea7b3146103f65780630ab319e8146104245780631332f1b814610450578063165ec2e21461046d57806318160ddd1461047557806318e97fd11461048f57806323b872dd146105045780632526c9331461053a57806327fc0cff1461056c5780632f745c59146106105780633f4ba83a1461063c57806342842e0e1461064457806345a32c861461067a5780634f6ccce7146106a05780635c975abb146106bd5780635facb882146106c55780636352211e146106e257806363ad2b6a146106ff5780636559e59a1461071c57806370a082311461074257806370c31afc1461076857806380a4edda146107855780638456cb59146107b15780638da5cb5b146107b957806395d89b41146107c1578063975057e7146107c95780639d118770146107d1578063a224c745146107ee578063a22cb46514610814578063a4e2ee1114610842578063aca910e71461085f578063b5aaa9d514610893578063b71c34d5146108b0578063b88d4fde146108ea578063ba00a33014610978578063c0d8012c146109a4578063c87b56dd146109c1578063cc55578e146109de578063dde5c1c714610a01578063e261ed7714610a1e578063e985e9c514610aaf578063ec046d0a14610add578063f2fde38b14610bac578063f3fd860514610bd2578063f421b0e914610bf7578063fbca0ce114610c14575b600080fd5b6102756004803603602081101561026457600080fd5b5035600160e060020a031916610c1c565b604080519115158252519081900360200190f35b6102756004803603608081101561029f57600080fd5b81359160208101359160408201359190810190608081016060820135602060020a8111156102cc57600080fd5b8201836020820111156102de57600080fd5b803590602001918460018302840111602060020a831117156102ff57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610c3f945050505050565b610348610c7f565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561038257818101518382015260200161036a565b50505050905090810190601f1680156103af5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103da600480360360208110156103d357600080fd5b5035610d14565b60408051600160a060020a039092168252519081900360200190f35b6104226004803603604081101561040c57600080fd5b50600160a060020a038135169060200135610df8565b005b6104226004803603604081101561043a57600080fd5b50600160a060020a038135169060200135610f0f565b6104226004803603602081101561046657600080fd5b5035610fff565b6103da611141565b61047d611150565b60408051918252519081900360200190f35b610422600480360360408110156104a557600080fd5b81359190810190604081016020820135602060020a8111156104c657600080fd5b8201836020820111156104d857600080fd5b803590602001918460018302840111602060020a831117156104f957600080fd5b509092509050611157565b6104226004803603606081101561051a57600080fd5b50600160a060020a038135811691602081013590911690604001356112a6565b6104226004803603606081101561055057600080fd5b50803590600160a060020a0360208201351690604001356112b6565b6104226004803603602081101561058257600080fd5b810190602081018135602060020a81111561059c57600080fd5b8201836020820111156105ae57600080fd5b803590602001918460018302840111602060020a831117156105cf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611393945050505050565b61047d6004803603604081101561062657600080fd5b50600160a060020a0381351690602001356114b6565b61042261157b565b6104226004803603606081101561065a57600080fd5b50600160a060020a0381358116916020810135909116906040013561164a565b61047d6004803603602081101561069057600080fd5b5035600160a060020a0316611665565b61047d600480360360208110156106b657600080fd5b5035611677565b61027561170d565b61047d600480360360208110156106db57600080fd5b503561171d565b6103da600480360360208110156106f857600080fd5b50356117be565b6102756004803603602081101561071557600080fd5b5035611850565b6104226004803603602081101561073257600080fd5b5035600160a060020a03166118f1565b61047d6004803603602081101561075857600080fd5b5035600160a060020a03166119d7565b61047d6004803603602081101561077e57600080fd5b5035611a6f565b6102756004803603604081101561079b57600080fd5b5080359060200135600160a060020a0316611b0d565b610422611b64565b6103da611c3a565b610348611c49565b6103da611ca7565b610422600480360360208110156107e757600080fd5b5035611cb6565b6104226004803603602081101561080457600080fd5b5035600160a060020a0316611e73565b6104226004803603604081101561082a57600080fd5b50600160a060020a0381351690602001351515611f5d565b6103da6004803603602081101561085857600080fd5b5035611fcb565b6104226004803603606081101561087557600080fd5b50600160a060020a0381351690602081013590604001351515612072565b610422600480360360208110156108a957600080fd5b50356121f4565b610422600480360360808110156108c657600080fd5b50803590600160a060020a03602082013516906040810135151590606001356122c4565b6104226004803603608081101561090057600080fd5b600160a060020a03823581169260208101359091169160408201359190810190608081016060820135602060020a81111561093a57600080fd5b82018360208201111561094c57600080fd5b803590602001918460018302840111602060020a8311171561096d57600080fd5b509092509050612423565b6102756004803603604081101561098e57600080fd5b50600160a060020a03813516906020013561246c565b61047d600480360360208110156109ba57600080fd5b5035612505565b610348600480360360208110156109d757600080fd5b5035612517565b6103da600480360360408110156109f457600080fd5b508035906020013561273d565b61047d60048036036020811015610a1757600080fd5b50356127ef565b61047d600480360360a0811015610a3457600080fd5b8135916020810135916040820135151591600160a060020a036060820135169181019060a081016080820135602060020a811115610a7157600080fd5b820183602082011115610a8357600080fd5b803590602001918460018302840111602060020a83111715610aa457600080fd5b509092509050612890565b61027560048036036040811015610ac557600080fd5b50600160a060020a0381358116916020013516612a6a565b61047d600480360360e0811015610af357600080fd5b813591602081013591810190606081016040820135602060020a811115610b1957600080fd5b820183602082011115610b2b57600080fd5b803590602001918460018302840111602060020a83111715610b4c57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050600160a060020a0383358116945060208401359360408101351515935060600135169050612a98565b61042260048036036020811015610bc257600080fd5b5035600160a060020a0316612ee1565b61042260048036036040811015610be857600080fd5b50803590602001351515613034565b61027560048036036020811015610c0d57600080fd5b50356130ba565b6103486130e3565b600160e060020a0319811660009081526020819052604090205460ff165b919050565b6000848152600e60209081526040808320858452909152812054600160a060020a0316610c6c8584613171565b600160a060020a03161495945050505050565b60018054604080516020601f60026000196101008789161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b820191906000526020600020905b815481529060010190602001808311610ced57829003601f168201915b5050505050905090565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316610ddb5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610da0578181015183820152602001610d88565b50505050905090810190601f168015610dcd5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050600090815260096020526040902054600160a060020a031690565b600081815260086020526040902054600160a060020a031633811480610e415750600160a060020a0381166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d060020a653030363030330281525090610eb25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000828152600960205260408082208054600160a060020a031916600160a060020a0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a6530313730303102918301919091526001919082168214610fb35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a0383166000818152600b6020526040808220805486179055518492917fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f91a3505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461107c5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008181526010602052604090205460ff1661109857600080fd5b6000818152601060209081526040808320805460ff19169055600c54600983528184208054600160a060020a031916600160a060020a03928316179055600883528184205460129093529220546110f492918216911683613255565b60408051828152600060208201528151600080516020614005833981519152929181900390910190a16040805182815290516000805160206140258339815191529181900360200190a150565b601354600160a060020a031681565b6004545b90565b6000838152601260205260409020548390600160a060020a0316331461117c57600080fd5b600c5460a060020a900460ff161561119357600080fd5b6000848152600860209081526040918290205482518084019093526006835260d060020a653030373030330291830191909152600160a060020a031661121d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000848152600d60205260409020611237908484613e94565b507f931f495b9a8e5d8e61946ea5d61e021f636cfe213a801f97589c18c152e408bd84848460405180848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a150505050565b6112b1838383613255565b505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a653031373030310291830191909152600291908216821461135a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561137257600080fd5b61137c838561336b565b506000928352601160205260409092209190915550565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146114105760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5061141a8161351e565b7f2f1172752b4c027870f0c890ad9d16d3a4d3af09c120988bd8620ef750b124aa816040518080602001828103825283818151815260200191508051906020019080838360005b83811015611479578181015183820152602001611461565b50505050905090810190601f1680156114a65780820380516001836020036101000a031916815260200191505b509250505060405180910390a150565b600160a060020a038216600090815260066020818152604080842054815180830190925292815260d060020a6530303630303702918101919091529083106115425760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a038316600090815260066020526040902080548390811061156757fe5b906000526020600020015490505b92915050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146115f85760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1661160f57600080fd5b600c805460a060020a60ff02191690556040517f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3390600090a1565b6112b183838360405180602001604052806000815250613535565b600b6020526000908152604090205481565b600454604080518082019091526006815260d060020a6530303630303702602082015260009183106116ed5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600482815481106116fb57fe5b90600052602060002001549050919050565b600c5460a060020a900460ff1681565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166117a75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526012602052604090206001015490565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a0316908161184a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50919050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166118da5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526010602052604090205460ff1690565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461196e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060148054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252600c8282015260a060020a6b73746f72654164647265737302606083015251600080516020613fe58339815191529181900360800190a150565b604080518082019091526006815260d060020a65303036303031026020820152600090600160a060020a038316611a525760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600160a060020a031660009081526006602052604090205490565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316611af95760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50506000908152600f602052604090205490565b600082815260086020526040812054600160a060020a03908116908316811480611b5c5750600160a060020a038082166000908152600a602090815260408083209387168352929052205460ff165b949350505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611be15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1615611bf957600080fd5b600c805460a060020a60ff02191660a060020a1790556040517f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62590600090a1565b600c54600160a060020a031681565b60028054604080516020601f6000196101006001871615020190941685900493840181900481028201810190925282815260609390929091830182828015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b601454600160a060020a031681565b600c5460a060020a900460ff1615611ccd57600080fd5b6014546040805160e060020a6382300d89028152600481018490523360248201529051600160a060020a03909216916382300d89916044808201926020929091908290030181600087803b158015611d2457600080fd5b505af1158015611d38573d6000803e3d6000fd5b505050506040513d6020811015611d4e57600080fd5b5051611d5957600080fd5b611d62816136d4565b6000818152600f602090815260408083208390558051808301808352848252858552600d90935292209151611d98929190613f12565b506000818152600e6020908152604080832083805282528083208054600160a060020a031990811690915560018452818420805490911690558383526011909152812055611de4613f80565b506040805160608101825260008082526020808301828152838501838152868452601283529285902084518154600160a060020a031916600160a060020a039091161781559051600182015591516002909201919091558251848152925191927fbc3b3ac51ba6ff17c341408a0d6270952ecdd0bbbd47586aecc338d73af9d78d929081900390910190a15050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611ef05760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060138054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252601082820152608060020a6f77686974656c6973744164647265737302606083015251600080516020613fe58339815191529181900360800190a150565b336000818152600a60209081526040808320600160a060020a03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166120555760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600090815260126020526040902054600160a060020a031690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a65303137303031029183019190915260019190821682146121165760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b508115801561212d575033600160a060020a038516145b156121a757604080518082019091526006815260d160020a6518189b98181902602082015260018416156121a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505b600160a060020a0384166000818152600b602052604080822080548719169055518592917fbb71944f65b9a48cc7d835179fb5e874f29b60aa0195785fb54968d8dddef08a91a350505050565b600c5460a060020a900460ff161561220b57600080fd5b6000818152601260205260409020548190600160a060020a0316331461223057600080fd5b600082815260126020526040902060020154421061224d57600080fd5b60008281526012602081815260408084208054600984528286208054600160a060020a031916600160a060020a0392831617905560088452919094205492909152915461229f92918216911684613255565b6040805183815290516000805160206140258339815191529181900360200190a15050565b83336122d08282611b0d565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d02815250906123415760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561235957600080fd5b6000831161236657600080fd5b83156123a3576000868152600e6020908152604080832086845290915290208054600160a060020a031916600160a060020a0387161790556123cb565b6000868152600e6020908152604080832086845290915290208054600160a060020a03191690555b60408051878152600160a060020a0387166020820152851515818301526060810185905290517fd4fada85986a6a990ebf8397071db3525f738377b4b8d4c3e9c8847dd7c7bd409181900360800190a1505050505050565b61246585858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061353592505050565b5050505050565b600080821160405180604001604052806006815260200160d060020a6530313730303302815250906124e25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600160a060020a03919091166000908152600b602052604090205481161490565b60009081526011602052604090205490565b6000818152600860209081526040918290205482518084019093526006835260d060020a65303037303033029183019190915260609190600160a060020a03166125a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000828152600d6020526040902054600260001961010060018416150201909116041561266c576000828152600d602090815260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845290918301828280156126605780601f1061263557610100808354040283529160200191612660565b820191906000526020600020905b81548152906001019060200180831161264357829003601f168201915b50505050509050610c3a565b60036126778361396e565b60405160200180838054600181600116156101000203166002900480156126d55780601f106126b35761010080835404028352918201916126d5565b820191906000526020600020905b8154815290600101906020018083116126c1575b5050825160208401908083835b602083106127015780518252601f1990920191602091820191016126e2565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529050610c3a565b60008281526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166127c75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50506000918252600e60209081526040808420928452919052902054600160a060020a031690565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166128795760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526012602052604090206002015490565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a6530313730303102928401929092529091600291821682146129355760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561294d57600080fd5b6129908888600187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3f92505050565b61299957600080fd5b6040805160208082018b9052600160a060020a0388168284015282518083038401815260609092019092528051910120876129d382613a38565b146129dd57600080fd5b60008981526009602052604090208054600160a060020a0319163317905586612a29576000898152600e602090815260408083206001845290915290208054600160a060020a03191690555b600089815260086020526040902054612a4c90600160a060020a0316878b613255565b50505060009586525050601160205250506040822080549290555090565b600160a060020a039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a653031373030310292840192909252909160029182168214612b3d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1615612b5557600080fd5b8883612b618282611b0d565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d0281525090612bd25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008b8152601260209081526040918290206001015482518084019093526006835260d160020a6518181b98181b029183019190915215612c585760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008b8152600e6020908152604080832083805282528083208054600160a060020a031916600160a060020a038d161790558d8352600f82528083208d9055600d82529091208a514292612cb19291908d0190613f12565b506013546040805160e060020a6387159d9b028152600481018f9052600160a060020a038981166024830152915191909216916387159d9b91604480830192600092919082900301818387803b158015612d0a57600080fd5b505af1158015612d1e573d6000803e3d6000fd5b505050508615612d5c5760008c8152600e602090815260408083206001845290915290208054600160a060020a031916600160a060020a038b161790555b612d64613f80565b604051806060016040528088600160a060020a031681526020018381526020018a815250905080601260008f815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010155604082015181600201559050507f0166db8152debe7d1cfed1b1e12a32a28a986839ab44dff49682be23e29704de8d8d8d8d8d8d88604051808881526020018781526020018060200186600160a060020a0316600160a060020a0316815260200185815260200184151515158152602001838152602001828103825287818151815260200191508051906020019080838360005b83811015612e81578181015183820152602001612e69565b50505050905090810190601f168015612eae5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390a15050506000998a5250506011602052505060409095205495945050505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314612f5e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50604080518082019091526006815260d160020a6518189c181819026020820152600160a060020a038216612fd75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c8054600160a060020a031916600160a060020a0392909216919091179055565b600c5460a060020a900460ff161561304b57600080fd5b6000828152601260205260409020548290600160a060020a0316331461307057600080fd5b600083815260106020908152604091829020805460ff19168515159081179091558251868152918201528151600080516020614005833981519152929181900390910190a1505050565b6000908152600e6020908152604080832060018452909152902054600160a060020a0316151590565b6003805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156131695780601f1061313e57610100808354040283529160200191613169565b820191906000526020600020905b81548152906001019060200180831161314c57829003601f168201915b505050505081565b6000815160411461318457506000611575565b60208201516040830151606084015160001a6fa2a8918ca85bafe22016d0b997e4df6060ff60020a038211156131c05760009350505050611575565b8060ff16601b141580156131d857508060ff16601c14155b156131e95760009350505050611575565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa158015613240573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6014546040805160e160020a6372331c73028152600160a060020a0386811660048301528581166024830152604482018590529151919092169163e46638e69160648083019260209291908290030181600087803b1580156132b657600080fd5b505af11580156132ca573d6000803e3d6000fd5b505050506040513d60208110156132e057600080fd5b50516132eb57600080fd5b6132f6838383613a89565b6013546040805160e060020a6387159d9b02815260048101849052600160a060020a038681166024830152915191909216916387159d9b91604480830192600092919082900301818387803b15801561334e57600080fd5b505af1158015613362573d6000803e3d6000fd5b50505050505050565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a0383166133e35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b18181b0291830191909152600160a060020a03161561346f5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008181526008602090815260408083208054600160a060020a031916600160a060020a038716908117909155808452600683528184208054600181810183559186528486208101879055868652600785528386205560048054918201908190557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b8201879055600590945282852055905191928492600080516020614045833981519152908290a4505050565b8051613531906003906020840190613f12565b5050565b61354783600160a060020a0316613e8e565b156136c35760405160e160020a630a85bd01028082523360048301818152600160a060020a0388811660248601526044850187905260806064860190815286516084870152865194959189169463150b7a0294938b938a938a93909160a40190602085019080838360005b838110156135ca5781810151838201526020016135b2565b50505050905090810190601f1680156135f75780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561361957600080fd5b505af115801561362d573d6000803e3d6000fd5b505050506040513d602081101561364357600080fd5b5051604080518082019091526006815260d060020a6530303630303502602082015291600160e060020a0319909116146136c15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505b6136ce848484613255565b50505050565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a031690816137605760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600082815260096020526040902054600160a060020a03161561379b5760008281526009602052604090208054600160a060020a03191690555b600160a060020a0381166000908152600660205260409020546137ba57fe5b600082815260076020908152604080832054600160a060020a0385168452600690925282205490916000199091019081831461387357600160a060020a038416600090815260066020526040902080548390811061381457fe5b90600052602060002001549050806006600086600160a060020a0316600160a060020a03168152602001908152602001600020848154811061385257fe5b60009182526020808320909101929092558281526007909152604090208390555b60008581526008602090815260408083208054600160a060020a031916905560078252808320839055600160a060020a0387168352600690915290208054906138c0906000198301613faa565b506004546138ca57fe5b6000858152600560205260409020546004805460001981019450849081106138ee57fe5b90600052602060002001549150816004828154811061390957fe5b6000918252602090912001556004805490613928906000198301613faa565b5060008281526005602052604080822083905587825280822082905551879190600160a060020a03881690600080516020614045833981519152908390a4505050505050565b6060816139965750604080518082019091526001815260fc60020a6003026020820152610c3a565b8160005b81156139ae57600101600a8204915061399a565b6060816040519080825280601f01601f1916602001820160405280156139db576020820181803883390190505b50859350905060001982015b8315613a2f57600a840660300160f860020a0282828060019003935081518110613a0d57fe5b6020010190600160f860020a031916908160001a905350600a840493506139e7565b50949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038416613b015760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a03858116911614613b915760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038316613c0a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a038316331480613c385750600081815260096020526040902054600160a060020a031633145b80613c665750600160a060020a0383166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d260020a650c0c0d8c0c0d0281525090613cd75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600081815260096020526040902054600160a060020a031615613d125760008181526009602052604090208054600160a060020a03191690555b600160a060020a038316600090815260066020526040902054613d3157fe5b600081815260076020908152604080832054600160a060020a038716845260069092529091205460001901808214613de557600160a060020a0385166000908152600660205260408120805483908110613d8757fe5b90600052602060002001549050806006600088600160a060020a0316600160a060020a031681526020019081526020016000208481548110613dc557fe5b600091825260208083209091019290925591825260079052604090208290555b600160a060020a0385166000908152600660205260409020805490613e0e906000198301613faa565b5060008381526008602090815260408083208054600160a060020a031916600160a060020a038981169182179092558085526006845282852080546001810180835591875285872081018a9055898752600790955283862094909455915192938793918a16916000805160206140458339815191529190a4505050505050565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613ed55782800160ff19823516178555613f02565b82800160010185558215613f02579182015b82811115613f02578235825591602001919060010190613ee7565b50613f0e929150613fca565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613f5357805160ff1916838001178555613f02565b82800160010185558215613f02579182015b82811115613f02578251825591602001919060010190613f65565b60405180606001604052806000600160a060020a0316815260200160008152602001600081525090565b8154818355818111156112b1576000838152602090206112b19181019083015b61115491905b80821115613f0e5760008155600101613fd056feb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb9651106eb2a6b59bafdf7d5d15a5fe2681abd76406ddf85d0af873cd23c221014dc3211cd3c497c4ee51feb1ed7bbb2d072b8c18bce7bbf0cf03d310a12b4afcd9818ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820e9896e5a1e3faba7c7f12686854a548c7a25f66710bc5a5f38be182b40660cd80029