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-11T13:02:45.552447Z
Constructor Arguments
0000000000000000000000003579669219dc20aa79e74eefd5fb2ecb0ce5fe0d
Arg [0] (address) : 0x3579669219dc20aa79e74eefd5fb2ecb0ce5fe0d
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/tokens/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;
constructor() public {
Ownable(msg.sender);
}
/**
* @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/tokens/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/tokens/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_XCERT = "007003";
string constant NFT_ALREADY_SET = "007006";
string constant NOT_OWNER_OR_OPERATOR = "007004";
/**
* Interface for all the connected contracts.
*/
ArianeeWhitelist arianeeWhitelist;
ArianeeStore 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_OWNER_OR_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_XCERT);
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){
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":"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":"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
0x6080604052600c805460a060020a60ff02191690553480156200002157600080fd5b5060405160208062004433833981018060405260208110156200004357600080fd5b50517f67be87c3ff9960ca1e9cfac5cab2ff4747269cf9ed20c9b7306235ac35a491c58054600160ff1991821681179092557ff7815fccbf112960a73756e185887fedcb9fc64ca0a16cc5923b7960ed78080080548216831790557f9562381dfbc2d8b8b66e765249f330164b73e329e5f01670660643571d1974df80548216831790557f77b7bbe0e49b76487c9476b5db3354cf5270619d0037ccb899c2a4c4a75b4318805490911682179055336000818152600b6020526040808220849055517fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f9190a3600c8054600160a060020a031916331790556040805180820190915260138082527f417269616e656520536d6172742d41737365740000000000000000000000000060209092019182526200018191600191620003be565b506040805180820190915260068082527f41726961534100000000000000000000000000000000000000000000000000006020909201918252620001c891600291620003be565b50620001dd8164010000000062000233810204565b6200022c6040518060400160405280601981526020017f68747470733a2f2f636572742e617269616e65652e6f72672f00000000000000815250620003a5640100000000026401000000009004565b5062000463565b600c5460408051808201909152600681527f3031383030310000000000000000000000000000000000000000000000000000602082015290600160a060020a031633146200031c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620002e0578181015183820152602001620002c6565b50505050905090810190601f1680156200030e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060138054600160a060020a038316600160a060020a031990911681179091556040805160208101929092528082526010828201527f77686974656c69737441646472657373000000000000000000000000000000006060830152517fb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb965119181900360800190a150565b8051620003ba906003906020840190620003be565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200040157805160ff191683800117855562000431565b8280016001018555821562000431579182015b828111156200043157825182559160200191906001019062000414565b506200043f92915062000443565b5090565b6200046091905b808211156200043f57600081556001016200044a565b90565b613fc080620004736000396000f3fe608060405234801561001057600080fd5b50600436106102335760e060020a600035046301ffc9a781146102385780630657a5ea1461027357806306fdde031461032a578063081812fc146103a7578063095ea7b3146103e05780630ab319e81461040e5780631332f1b81461043a57806318160ddd1461045757806318e97fd11461047157806323b872dd146104e65780632526c9331461051c57806327fc0cff1461054e5780632f745c59146105f25780633f4ba83a1461061e57806342842e0e1461062657806345a32c861461065c5780634f6ccce7146106825780635c975abb1461069f5780635facb882146106a75780636352211e146106c457806363ad2b6a146106e15780636559e59a146106fe57806370a082311461072457806370c31afc1461074a57806380a4edda146107675780638456cb59146107935780638da5cb5b1461079b57806395d89b41146107a35780639d118770146107ab578063a224c745146107c8578063a22cb465146107ee578063a4e2ee111461081c578063aca910e714610839578063b5aaa9d51461086d578063b71c34d51461088a578063b88d4fde146108c4578063ba00a33014610952578063c0d8012c1461097e578063c87b56dd1461099b578063cc55578e146109b8578063dde5c1c7146109db578063e261ed77146109f8578063e985e9c514610a89578063ec046d0a14610ab7578063f2fde38b14610b86578063f3fd860514610bac578063f421b0e914610bd1578063fbca0ce114610bee575b600080fd5b61025f6004803603602081101561024e57600080fd5b5035600160e060020a031916610bf6565b604080519115158252519081900360200190f35b61025f6004803603608081101561028957600080fd5b81359160208101359160408201359190810190608081016060820135602060020a8111156102b657600080fd5b8201836020820111156102c857600080fd5b803590602001918460018302840111602060020a831117156102e957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610c19945050505050565b610332610c59565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561036c578181015183820152602001610354565b50505050905090810190601f1680156103995780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103c4600480360360208110156103bd57600080fd5b5035610cee565b60408051600160a060020a039092168252519081900360200190f35b61040c600480360360408110156103f657600080fd5b50600160a060020a038135169060200135610dd2565b005b61040c6004803603604081101561042457600080fd5b50600160a060020a038135169060200135610ee9565b61040c6004803603602081101561045057600080fd5b5035610fd9565b61045f61111b565b60408051918252519081900360200190f35b61040c6004803603604081101561048757600080fd5b81359190810190604081016020820135602060020a8111156104a857600080fd5b8201836020820111156104ba57600080fd5b803590602001918460018302840111602060020a831117156104db57600080fd5b509092509050611122565b61040c600480360360608110156104fc57600080fd5b50600160a060020a03813581169160208101359091169060400135611271565b61040c6004803603606081101561053257600080fd5b50803590600160a060020a036020820135169060400135611281565b61040c6004803603602081101561056457600080fd5b810190602081018135602060020a81111561057e57600080fd5b82018360208201111561059057600080fd5b803590602001918460018302840111602060020a831117156105b157600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061135e945050505050565b61045f6004803603604081101561060857600080fd5b50600160a060020a038135169060200135611481565b61040c611546565b61040c6004803603606081101561063c57600080fd5b50600160a060020a03813581169160208101359091169060400135611615565b61045f6004803603602081101561067257600080fd5b5035600160a060020a0316611630565b61045f6004803603602081101561069857600080fd5b5035611642565b61025f6116d8565b61045f600480360360208110156106bd57600080fd5b50356116e8565b6103c4600480360360208110156106da57600080fd5b5035611789565b61025f600480360360208110156106f757600080fd5b503561181b565b61040c6004803603602081101561071457600080fd5b5035600160a060020a03166118bc565b61045f6004803603602081101561073a57600080fd5b5035600160a060020a03166119a2565b61045f6004803603602081101561076057600080fd5b5035611a3a565b61025f6004803603604081101561077d57600080fd5b5080359060200135600160a060020a0316611ad8565b61040c611b2f565b6103c4611c05565b610332611c14565b61040c600480360360208110156107c157600080fd5b5035611c72565b61040c600480360360208110156107de57600080fd5b5035600160a060020a0316611e2f565b61040c6004803603604081101561080457600080fd5b50600160a060020a0381351690602001351515611f19565b6103c46004803603602081101561083257600080fd5b5035611f87565b61040c6004803603606081101561084f57600080fd5b50600160a060020a038135169060208101359060400135151561202e565b61040c6004803603602081101561088357600080fd5b50356121b0565b61040c600480360360808110156108a057600080fd5b50803590600160a060020a0360208201351690604081013515159060600135612280565b61040c600480360360808110156108da57600080fd5b600160a060020a03823581169260208101359091169160408201359190810190608081016060820135602060020a81111561091457600080fd5b82018360208201111561092657600080fd5b803590602001918460018302840111602060020a8311171561094757600080fd5b5090925090506123df565b61025f6004803603604081101561096857600080fd5b50600160a060020a038135169060200135612428565b61045f6004803603602081101561099457600080fd5b50356124c1565b610332600480360360208110156109b157600080fd5b50356124d3565b6103c4600480360360408110156109ce57600080fd5b508035906020013561266d565b61045f600480360360208110156109f157600080fd5b503561271f565b61045f600480360360a0811015610a0e57600080fd5b8135916020810135916040820135151591600160a060020a036060820135169181019060a081016080820135602060020a811115610a4b57600080fd5b820183602082011115610a5d57600080fd5b803590602001918460018302840111602060020a83111715610a7e57600080fd5b5090925090506127c0565b61025f60048036036040811015610a9f57600080fd5b50600160a060020a038135811691602001351661299a565b61045f600480360360e0811015610acd57600080fd5b813591602081013591810190606081016040820135602060020a811115610af357600080fd5b820183602082011115610b0557600080fd5b803590602001918460018302840111602060020a83111715610b2657600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050600160a060020a03833581169450602084013593604081013515159350606001351690506129c8565b61040c60048036036020811015610b9c57600080fd5b5035600160a060020a0316612e11565b61040c60048036036040811015610bc257600080fd5b50803590602001351515612f64565b61025f60048036036020811015610be757600080fd5b5035612fea565b610332613013565b600160e060020a0319811660009081526020819052604090205460ff165b919050565b6000848152600e60209081526040808320858452909152812054600160a060020a0316610c4685846130a1565b600160a060020a03161495945050505050565b60018054604080516020601f60026000196101008789161502019095169490940493840181900481028201810190925282815260609390929091830182828015610ce45780601f10610cb957610100808354040283529160200191610ce4565b820191906000526020600020905b815481529060010190602001808311610cc757829003601f168201915b5050505050905090565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316610db55760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610d7a578181015183820152602001610d62565b50505050905090810190601f168015610da75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050600090815260096020526040902054600160a060020a031690565b600081815260086020526040902054600160a060020a031633811480610e1b5750600160a060020a0381166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d060020a653030363030330281525090610e8c5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506000828152600960205260408082208054600160a060020a031916600160a060020a0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a6530313730303102918301919091526001919082168214610f8d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600160a060020a0383166000818152600b6020526040808220805486179055518492917fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f91a3505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146110565760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060008181526010602052604090205460ff1661107257600080fd5b6000818152601060209081526040808320805460ff19169055600c54600983528184208054600160a060020a031916600160a060020a03928316179055600883528184205460129093529220546110ce92918216911683613185565b60408051828152600060208201528151600080516020613f35833981519152929181900390910190a1604080518281529051600080516020613f558339815191529181900360200190a150565b6004545b90565b6000838152601260205260409020548390600160a060020a0316331461114757600080fd5b600c5460a060020a900460ff161561115e57600080fd5b6000848152600860209081526040918290205482518084019093526006835260d060020a653030373030330291830191909152600160a060020a03166111e85760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506000848152600d60205260409020611202908484613dc4565b507f931f495b9a8e5d8e61946ea5d61e021f636cfe213a801f97589c18c152e408bd84848460405180848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a150505050565b61127c838383613185565b505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a65303137303031029183019190915260029190821682146113255760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff161561133d57600080fd5b611347838561329b565b506000928352601160205260409092209190915550565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146113db5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506113e58161344e565b7f2f1172752b4c027870f0c890ad9d16d3a4d3af09c120988bd8620ef750b124aa816040518080602001828103825283818151815260200191508051906020019080838360005b8381101561144457818101518382015260200161142c565b50505050905090810190601f1680156114715780820380516001836020036101000a031916815260200191505b509250505060405180910390a150565b600160a060020a038216600090815260066020818152604080842054815180830190925292815260d060020a65303036303037029181019190915290831061150d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600160a060020a038316600090815260066020526040902080548390811061153257fe5b906000526020600020015490505b92915050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146115c35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff166115da57600080fd5b600c805460a060020a60ff02191690556040517f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3390600090a1565b61127c83838360405180602001604052806000815250613465565b600b6020526000908152604090205481565b600454604080518082019091526006815260d060020a6530303630303702602082015260009183106116b85760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600482815481106116c657fe5b90600052602060002001549050919050565b600c5460a060020a900460ff1681565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166117725760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505060009081526012602052604090206001015490565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a031690816118155760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50919050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166118a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505060009081526010602052604090205460ff1690565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146119395760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060148054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252600c8282015260a060020a6b73746f72654164647265737302606083015251600080516020613f158339815191529181900360800190a150565b604080518082019091526006815260d060020a65303036303031026020820152600090600160a060020a038316611a1d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5050600160a060020a031660009081526006602052604090205490565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316611ac45760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50506000908152600f602052604090205490565b600082815260086020526040812054600160a060020a03908116908316811480611b275750600160a060020a038082166000908152600a602090815260408083209387168352929052205460ff165b949350505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611bac5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff1615611bc457600080fd5b600c805460a060020a60ff02191660a060020a1790556040517f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62590600090a1565b600c54600160a060020a031681565b60028054604080516020601f6000196101006001871615020190941685900493840181900481028201810190925282815260609390929091830182828015610ce45780601f10610cb957610100808354040283529160200191610ce4565b600c5460a060020a900460ff1615611c8957600080fd5b6014546040805160e060020a6382300d89028152600481018490523360248201529051600160a060020a03909216916382300d89916044808201926020929091908290030181600087803b158015611ce057600080fd5b505af1158015611cf4573d6000803e3d6000fd5b505050506040513d6020811015611d0a57600080fd5b5051611d1557600080fd5b611d1e81613604565b6000818152600f602090815260408083208390558051808301808352848252858552600d90935292209151611d54929190613e42565b506000818152600e6020908152604080832083805282528083208054600160a060020a031990811690915560018452818420805490911690558383526011909152812055611da0613eb0565b506040805160608101825260008082526020808301828152838501838152868452601283529285902084518154600160a060020a031916600160a060020a039091161781559051600182015591516002909201919091558251848152925191927fbc3b3ac51ba6ff17c341408a0d6270952ecdd0bbbd47586aecc338d73af9d78d929081900390910190a15050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611eac5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060138054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252601082820152608060020a6f77686974656c6973744164647265737302606083015251600080516020613f158339815191529181900360800190a150565b336000818152600a60209081526040808320600160a060020a03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166120115760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5050600090815260126020526040902054600160a060020a031690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a65303137303031029183019190915260019190821682146120d25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50811580156120e9575033600160a060020a038516145b1561216357604080518082019091526006815260d160020a6518189b98181902602082015260018416156121615760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505b600160a060020a0384166000818152600b602052604080822080548719169055518592917fbb71944f65b9a48cc7d835179fb5e874f29b60aa0195785fb54968d8dddef08a91a350505050565b600c5460a060020a900460ff16156121c757600080fd5b6000818152601260205260409020548190600160a060020a031633146121ec57600080fd5b600082815260126020526040902060020154421061220957600080fd5b60008281526012602081815260408084208054600984528286208054600160a060020a031916600160a060020a0392831617905560088452919094205492909152915461225b92918216911684613185565b604080518381529051600080516020613f558339815191529181900360200190a15050565b833361228c8282611ad8565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d02815250906122fd5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff161561231557600080fd5b6000831161232257600080fd5b831561235f576000868152600e6020908152604080832086845290915290208054600160a060020a031916600160a060020a038716179055612387565b6000868152600e6020908152604080832086845290915290208054600160a060020a03191690555b60408051878152600160a060020a0387166020820152851515818301526060810185905290517fd4fada85986a6a990ebf8397071db3525f738377b4b8d4c3e9c8847dd7c7bd409181900360800190a1505050505050565b61242185858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061346592505050565b5050505050565b600080821160405180604001604052806006815260200160d060020a65303137303033028152509061249e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5050600160a060020a03919091166000908152600b602052604090205481161490565b60009081526011602052604090205490565b6000818152600d6020526040902054606090600260001961010060018416150201909116041561259c576000828152600d602090815260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845290918301828280156125905780601f1061256557610100808354040283529160200191612590565b820191906000526020600020905b81548152906001019060200180831161257357829003601f168201915b50505050509050610c14565b60036125a78361389e565b60405160200180838054600181600116156101000203166002900480156126055780601f106125e3576101008083540402835291820191612605565b820191906000526020600020905b8154815290600101906020018083116125f1575b5050825160208401908083835b602083106126315780518252601f199092019160209182019101612612565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529050610c14565b60008281526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166126f75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50506000918252600e60209081526040808420928452919052902054600160a060020a031690565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166127a95760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505060009081526012602052604090206002015490565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a6530313730303102928401929092529091600291821682146128655760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff161561287d57600080fd5b6128c08888600187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c1992505050565b6128c957600080fd5b6040805160208082018b9052600160a060020a03881682840152825180830384018152606090920190925280519101208761290382613968565b1461290d57600080fd5b60008981526009602052604090208054600160a060020a0319163317905586612959576000898152600e602090815260408083206001845290915290208054600160a060020a03191690555b60008981526008602052604090205461297c90600160a060020a0316878b613185565b50505060009586525050601160205250506040822080549290555090565b600160a060020a039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a653031373030310292840192909252909160029182168214612a6d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff1615612a8557600080fd5b8883612a918282611ad8565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d0281525090612b025760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060008b8152601260209081526040918290206001015482518084019093526006835260d160020a6518181b98181b029183019190915215612b885760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060008b8152600e6020908152604080832083805282528083208054600160a060020a031916600160a060020a038d161790558d8352600f82528083208d9055600d82529091208a514292612be19291908d0190613e42565b506013546040805160e060020a6387159d9b028152600481018f9052600160a060020a038981166024830152915191909216916387159d9b91604480830192600092919082900301818387803b158015612c3a57600080fd5b505af1158015612c4e573d6000803e3d6000fd5b505050508615612c8c5760008c8152600e602090815260408083206001845290915290208054600160a060020a031916600160a060020a038b161790555b612c94613eb0565b604051806060016040528088600160a060020a031681526020018381526020018a815250905080601260008f815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010155604082015181600201559050507f0166db8152debe7d1cfed1b1e12a32a28a986839ab44dff49682be23e29704de8d8d8d8d8d8d88604051808881526020018781526020018060200186600160a060020a0316600160a060020a0316815260200185815260200184151515158152602001838152602001828103825287818151815260200191508051906020019080838360005b83811015612db1578181015183820152602001612d99565b50505050905090810190601f168015612dde5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390a15050506000998a5250506011602052505060409095205495945050505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314612e8e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50604080518082019091526006815260d160020a6518189c181819026020820152600160a060020a038216612f075760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c8054600160a060020a031916600160a060020a0392909216919091179055565b600c5460a060020a900460ff1615612f7b57600080fd5b6000828152601260205260409020548290600160a060020a03163314612fa057600080fd5b600083815260106020908152604091829020805460ff19168515159081179091558251868152918201528151600080516020613f35833981519152929181900390910190a1505050565b6000908152600e6020908152604080832060018452909152902054600160a060020a0316151590565b6003805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156130995780601f1061306e57610100808354040283529160200191613099565b820191906000526020600020905b81548152906001019060200180831161307c57829003601f168201915b505050505081565b600081516041146130b457506000611540565b60208201516040830151606084015160001a6fa2a8918ca85bafe22016d0b997e4df6060ff60020a038211156130f05760009350505050611540565b8060ff16601b1415801561310857508060ff16601c14155b156131195760009350505050611540565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa158015613170573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6014546040805160e160020a6372331c73028152600160a060020a0386811660048301528581166024830152604482018590529151919092169163e46638e69160648083019260209291908290030181600087803b1580156131e657600080fd5b505af11580156131fa573d6000803e3d6000fd5b505050506040513d602081101561321057600080fd5b505161321b57600080fd5b6132268383836139b9565b6013546040805160e060020a6387159d9b02815260048101849052600160a060020a038681166024830152915191909216916387159d9b91604480830192600092919082900301818387803b15801561327e57600080fd5b505af1158015613292573d6000803e3d6000fd5b50505050505050565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a0383166133135760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b18181b0291830191909152600160a060020a03161561339f5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060008181526008602090815260408083208054600160a060020a031916600160a060020a038716908117909155808452600683528184208054600181810183559186528486208101879055868652600785528386205560048054918201908190557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b8201879055600590945282852055905191928492600080516020613f75833981519152908290a4505050565b8051613461906003906020840190613e42565b5050565b61347783600160a060020a0316613dbe565b156135f35760405160e160020a630a85bd01028082523360048301818152600160a060020a0388811660248601526044850187905260806064860190815286516084870152865194959189169463150b7a0294938b938a938a93909160a40190602085019080838360005b838110156134fa5781810151838201526020016134e2565b50505050905090810190601f1680156135275780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561354957600080fd5b505af115801561355d573d6000803e3d6000fd5b505050506040513d602081101561357357600080fd5b5051604080518082019091526006815260d060020a6530303630303502602082015291600160e060020a0319909116146135f15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505b6135fe848484613185565b50505050565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a031690816136905760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600082815260096020526040902054600160a060020a0316156136cb5760008281526009602052604090208054600160a060020a03191690555b600160a060020a0381166000908152600660205260409020546136ea57fe5b600082815260076020908152604080832054600160a060020a038516845260069092528220549091600019909101908183146137a357600160a060020a038416600090815260066020526040902080548390811061374457fe5b90600052602060002001549050806006600086600160a060020a0316600160a060020a03168152602001908152602001600020848154811061378257fe5b60009182526020808320909101929092558281526007909152604090208390555b60008581526008602090815260408083208054600160a060020a031916905560078252808320839055600160a060020a0387168352600690915290208054906137f0906000198301613eda565b506004546137fa57fe5b60008581526005602052604090205460048054600019810194508490811061381e57fe5b90600052602060002001549150816004828154811061383957fe5b6000918252602090912001556004805490613858906000198301613eda565b5060008281526005602052604080822083905587825280822082905551879190600160a060020a03881690600080516020613f75833981519152908390a4505050505050565b6060816138c65750604080518082019091526001815260fc60020a6003026020820152610c14565b8160005b81156138de57600101600a820491506138ca565b6060816040519080825280601f01601f19166020018201604052801561390b576020820181803883390190505b50859350905060001982015b831561395f57600a840660300160f860020a028282806001900393508151811061393d57fe5b6020010190600160f860020a031916908160001a905350600a84049350613917565b50949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038416613a315760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a03858116911614613ac15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038316613b3a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600160a060020a038316331480613b685750600081815260096020526040902054600160a060020a031633145b80613b965750600160a060020a0383166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d260020a650c0c0d8c0c0d0281525090613c075760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600081815260096020526040902054600160a060020a031615613c425760008181526009602052604090208054600160a060020a03191690555b600160a060020a038316600090815260066020526040902054613c6157fe5b600081815260076020908152604080832054600160a060020a038716845260069092529091205460001901808214613d1557600160a060020a0385166000908152600660205260408120805483908110613cb757fe5b90600052602060002001549050806006600088600160a060020a0316600160a060020a031681526020019081526020016000208481548110613cf557fe5b600091825260208083209091019290925591825260079052604090208290555b600160a060020a0385166000908152600660205260409020805490613d3e906000198301613eda565b5060008381526008602090815260408083208054600160a060020a031916600160a060020a038981169182179092558085526006845282852080546001810180835591875285872081018a9055898752600790955283862094909455915192938793918a1691600080516020613f758339815191529190a4505050505050565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613e055782800160ff19823516178555613e32565b82800160010185558215613e32579182015b82811115613e32578235825591602001919060010190613e17565b50613e3e929150613efa565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613e8357805160ff1916838001178555613e32565b82800160010185558215613e32579182015b82811115613e32578251825591602001919060010190613e95565b60405180606001604052806000600160a060020a0316815260200160008152602001600081525090565b81548183558181111561127c5760008381526020902061127c9181019083015b61111f91905b80821115613e3e5760008155600101613f0056feb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb9651106eb2a6b59bafdf7d5d15a5fe2681abd76406ddf85d0af873cd23c221014dc3211cd3c497c4ee51feb1ed7bbb2d072b8c18bce7bbf0cf03d310a12b4afcd9818ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820c32f070ed85d3f9edcab8129a948a3f68141137c3295d1133ed892061068a2e100290000000000000000000000003579669219dc20aa79e74eefd5fb2ecb0ce5fe0d
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106102335760e060020a600035046301ffc9a781146102385780630657a5ea1461027357806306fdde031461032a578063081812fc146103a7578063095ea7b3146103e05780630ab319e81461040e5780631332f1b81461043a57806318160ddd1461045757806318e97fd11461047157806323b872dd146104e65780632526c9331461051c57806327fc0cff1461054e5780632f745c59146105f25780633f4ba83a1461061e57806342842e0e1461062657806345a32c861461065c5780634f6ccce7146106825780635c975abb1461069f5780635facb882146106a75780636352211e146106c457806363ad2b6a146106e15780636559e59a146106fe57806370a082311461072457806370c31afc1461074a57806380a4edda146107675780638456cb59146107935780638da5cb5b1461079b57806395d89b41146107a35780639d118770146107ab578063a224c745146107c8578063a22cb465146107ee578063a4e2ee111461081c578063aca910e714610839578063b5aaa9d51461086d578063b71c34d51461088a578063b88d4fde146108c4578063ba00a33014610952578063c0d8012c1461097e578063c87b56dd1461099b578063cc55578e146109b8578063dde5c1c7146109db578063e261ed77146109f8578063e985e9c514610a89578063ec046d0a14610ab7578063f2fde38b14610b86578063f3fd860514610bac578063f421b0e914610bd1578063fbca0ce114610bee575b600080fd5b61025f6004803603602081101561024e57600080fd5b5035600160e060020a031916610bf6565b604080519115158252519081900360200190f35b61025f6004803603608081101561028957600080fd5b81359160208101359160408201359190810190608081016060820135602060020a8111156102b657600080fd5b8201836020820111156102c857600080fd5b803590602001918460018302840111602060020a831117156102e957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610c19945050505050565b610332610c59565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561036c578181015183820152602001610354565b50505050905090810190601f1680156103995780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103c4600480360360208110156103bd57600080fd5b5035610cee565b60408051600160a060020a039092168252519081900360200190f35b61040c600480360360408110156103f657600080fd5b50600160a060020a038135169060200135610dd2565b005b61040c6004803603604081101561042457600080fd5b50600160a060020a038135169060200135610ee9565b61040c6004803603602081101561045057600080fd5b5035610fd9565b61045f61111b565b60408051918252519081900360200190f35b61040c6004803603604081101561048757600080fd5b81359190810190604081016020820135602060020a8111156104a857600080fd5b8201836020820111156104ba57600080fd5b803590602001918460018302840111602060020a831117156104db57600080fd5b509092509050611122565b61040c600480360360608110156104fc57600080fd5b50600160a060020a03813581169160208101359091169060400135611271565b61040c6004803603606081101561053257600080fd5b50803590600160a060020a036020820135169060400135611281565b61040c6004803603602081101561056457600080fd5b810190602081018135602060020a81111561057e57600080fd5b82018360208201111561059057600080fd5b803590602001918460018302840111602060020a831117156105b157600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061135e945050505050565b61045f6004803603604081101561060857600080fd5b50600160a060020a038135169060200135611481565b61040c611546565b61040c6004803603606081101561063c57600080fd5b50600160a060020a03813581169160208101359091169060400135611615565b61045f6004803603602081101561067257600080fd5b5035600160a060020a0316611630565b61045f6004803603602081101561069857600080fd5b5035611642565b61025f6116d8565b61045f600480360360208110156106bd57600080fd5b50356116e8565b6103c4600480360360208110156106da57600080fd5b5035611789565b61025f600480360360208110156106f757600080fd5b503561181b565b61040c6004803603602081101561071457600080fd5b5035600160a060020a03166118bc565b61045f6004803603602081101561073a57600080fd5b5035600160a060020a03166119a2565b61045f6004803603602081101561076057600080fd5b5035611a3a565b61025f6004803603604081101561077d57600080fd5b5080359060200135600160a060020a0316611ad8565b61040c611b2f565b6103c4611c05565b610332611c14565b61040c600480360360208110156107c157600080fd5b5035611c72565b61040c600480360360208110156107de57600080fd5b5035600160a060020a0316611e2f565b61040c6004803603604081101561080457600080fd5b50600160a060020a0381351690602001351515611f19565b6103c46004803603602081101561083257600080fd5b5035611f87565b61040c6004803603606081101561084f57600080fd5b50600160a060020a038135169060208101359060400135151561202e565b61040c6004803603602081101561088357600080fd5b50356121b0565b61040c600480360360808110156108a057600080fd5b50803590600160a060020a0360208201351690604081013515159060600135612280565b61040c600480360360808110156108da57600080fd5b600160a060020a03823581169260208101359091169160408201359190810190608081016060820135602060020a81111561091457600080fd5b82018360208201111561092657600080fd5b803590602001918460018302840111602060020a8311171561094757600080fd5b5090925090506123df565b61025f6004803603604081101561096857600080fd5b50600160a060020a038135169060200135612428565b61045f6004803603602081101561099457600080fd5b50356124c1565b610332600480360360208110156109b157600080fd5b50356124d3565b6103c4600480360360408110156109ce57600080fd5b508035906020013561266d565b61045f600480360360208110156109f157600080fd5b503561271f565b61045f600480360360a0811015610a0e57600080fd5b8135916020810135916040820135151591600160a060020a036060820135169181019060a081016080820135602060020a811115610a4b57600080fd5b820183602082011115610a5d57600080fd5b803590602001918460018302840111602060020a83111715610a7e57600080fd5b5090925090506127c0565b61025f60048036036040811015610a9f57600080fd5b50600160a060020a038135811691602001351661299a565b61045f600480360360e0811015610acd57600080fd5b813591602081013591810190606081016040820135602060020a811115610af357600080fd5b820183602082011115610b0557600080fd5b803590602001918460018302840111602060020a83111715610b2657600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050600160a060020a03833581169450602084013593604081013515159350606001351690506129c8565b61040c60048036036020811015610b9c57600080fd5b5035600160a060020a0316612e11565b61040c60048036036040811015610bc257600080fd5b50803590602001351515612f64565b61025f60048036036020811015610be757600080fd5b5035612fea565b610332613013565b600160e060020a0319811660009081526020819052604090205460ff165b919050565b6000848152600e60209081526040808320858452909152812054600160a060020a0316610c4685846130a1565b600160a060020a03161495945050505050565b60018054604080516020601f60026000196101008789161502019095169490940493840181900481028201810190925282815260609390929091830182828015610ce45780601f10610cb957610100808354040283529160200191610ce4565b820191906000526020600020905b815481529060010190602001808311610cc757829003601f168201915b5050505050905090565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316610db55760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610d7a578181015183820152602001610d62565b50505050905090810190601f168015610da75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050600090815260096020526040902054600160a060020a031690565b600081815260086020526040902054600160a060020a031633811480610e1b5750600160a060020a0381166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d060020a653030363030330281525090610e8c5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506000828152600960205260408082208054600160a060020a031916600160a060020a0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a6530313730303102918301919091526001919082168214610f8d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600160a060020a0383166000818152600b6020526040808220805486179055518492917fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f91a3505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146110565760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060008181526010602052604090205460ff1661107257600080fd5b6000818152601060209081526040808320805460ff19169055600c54600983528184208054600160a060020a031916600160a060020a03928316179055600883528184205460129093529220546110ce92918216911683613185565b60408051828152600060208201528151600080516020613f35833981519152929181900390910190a1604080518281529051600080516020613f558339815191529181900360200190a150565b6004545b90565b6000838152601260205260409020548390600160a060020a0316331461114757600080fd5b600c5460a060020a900460ff161561115e57600080fd5b6000848152600860209081526040918290205482518084019093526006835260d060020a653030373030330291830191909152600160a060020a03166111e85760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506000848152600d60205260409020611202908484613dc4565b507f931f495b9a8e5d8e61946ea5d61e021f636cfe213a801f97589c18c152e408bd84848460405180848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a150505050565b61127c838383613185565b505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a65303137303031029183019190915260029190821682146113255760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff161561133d57600080fd5b611347838561329b565b506000928352601160205260409092209190915550565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146113db5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506113e58161344e565b7f2f1172752b4c027870f0c890ad9d16d3a4d3af09c120988bd8620ef750b124aa816040518080602001828103825283818151815260200191508051906020019080838360005b8381101561144457818101518382015260200161142c565b50505050905090810190601f1680156114715780820380516001836020036101000a031916815260200191505b509250505060405180910390a150565b600160a060020a038216600090815260066020818152604080842054815180830190925292815260d060020a65303036303037029181019190915290831061150d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600160a060020a038316600090815260066020526040902080548390811061153257fe5b906000526020600020015490505b92915050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146115c35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff166115da57600080fd5b600c805460a060020a60ff02191690556040517f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3390600090a1565b61127c83838360405180602001604052806000815250613465565b600b6020526000908152604090205481565b600454604080518082019091526006815260d060020a6530303630303702602082015260009183106116b85760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600482815481106116c657fe5b90600052602060002001549050919050565b600c5460a060020a900460ff1681565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166117725760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505060009081526012602052604090206001015490565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a031690816118155760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50919050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166118a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505060009081526010602052604090205460ff1690565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146119395760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060148054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252600c8282015260a060020a6b73746f72654164647265737302606083015251600080516020613f158339815191529181900360800190a150565b604080518082019091526006815260d060020a65303036303031026020820152600090600160a060020a038316611a1d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5050600160a060020a031660009081526006602052604090205490565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316611ac45760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50506000908152600f602052604090205490565b600082815260086020526040812054600160a060020a03908116908316811480611b275750600160a060020a038082166000908152600a602090815260408083209387168352929052205460ff165b949350505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611bac5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff1615611bc457600080fd5b600c805460a060020a60ff02191660a060020a1790556040517f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62590600090a1565b600c54600160a060020a031681565b60028054604080516020601f6000196101006001871615020190941685900493840181900481028201810190925282815260609390929091830182828015610ce45780601f10610cb957610100808354040283529160200191610ce4565b600c5460a060020a900460ff1615611c8957600080fd5b6014546040805160e060020a6382300d89028152600481018490523360248201529051600160a060020a03909216916382300d89916044808201926020929091908290030181600087803b158015611ce057600080fd5b505af1158015611cf4573d6000803e3d6000fd5b505050506040513d6020811015611d0a57600080fd5b5051611d1557600080fd5b611d1e81613604565b6000818152600f602090815260408083208390558051808301808352848252858552600d90935292209151611d54929190613e42565b506000818152600e6020908152604080832083805282528083208054600160a060020a031990811690915560018452818420805490911690558383526011909152812055611da0613eb0565b506040805160608101825260008082526020808301828152838501838152868452601283529285902084518154600160a060020a031916600160a060020a039091161781559051600182015591516002909201919091558251848152925191927fbc3b3ac51ba6ff17c341408a0d6270952ecdd0bbbd47586aecc338d73af9d78d929081900390910190a15050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611eac5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060138054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252601082820152608060020a6f77686974656c6973744164647265737302606083015251600080516020613f158339815191529181900360800190a150565b336000818152600a60209081526040808320600160a060020a03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166120115760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5050600090815260126020526040902054600160a060020a031690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a65303137303031029183019190915260019190821682146120d25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50811580156120e9575033600160a060020a038516145b1561216357604080518082019091526006815260d160020a6518189b98181902602082015260018416156121615760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505b600160a060020a0384166000818152600b602052604080822080548719169055518592917fbb71944f65b9a48cc7d835179fb5e874f29b60aa0195785fb54968d8dddef08a91a350505050565b600c5460a060020a900460ff16156121c757600080fd5b6000818152601260205260409020548190600160a060020a031633146121ec57600080fd5b600082815260126020526040902060020154421061220957600080fd5b60008281526012602081815260408084208054600984528286208054600160a060020a031916600160a060020a0392831617905560088452919094205492909152915461225b92918216911684613185565b604080518381529051600080516020613f558339815191529181900360200190a15050565b833361228c8282611ad8565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d02815250906122fd5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff161561231557600080fd5b6000831161232257600080fd5b831561235f576000868152600e6020908152604080832086845290915290208054600160a060020a031916600160a060020a038716179055612387565b6000868152600e6020908152604080832086845290915290208054600160a060020a03191690555b60408051878152600160a060020a0387166020820152851515818301526060810185905290517fd4fada85986a6a990ebf8397071db3525f738377b4b8d4c3e9c8847dd7c7bd409181900360800190a1505050505050565b61242185858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061346592505050565b5050505050565b600080821160405180604001604052806006815260200160d060020a65303137303033028152509061249e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5050600160a060020a03919091166000908152600b602052604090205481161490565b60009081526011602052604090205490565b6000818152600d6020526040902054606090600260001961010060018416150201909116041561259c576000828152600d602090815260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845290918301828280156125905780601f1061256557610100808354040283529160200191612590565b820191906000526020600020905b81548152906001019060200180831161257357829003601f168201915b50505050509050610c14565b60036125a78361389e565b60405160200180838054600181600116156101000203166002900480156126055780601f106125e3576101008083540402835291820191612605565b820191906000526020600020905b8154815290600101906020018083116125f1575b5050825160208401908083835b602083106126315780518252601f199092019160209182019101612612565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529050610c14565b60008281526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166126f75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50506000918252600e60209081526040808420928452919052902054600160a060020a031690565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166127a95760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505060009081526012602052604090206002015490565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a6530313730303102928401929092529091600291821682146128655760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff161561287d57600080fd5b6128c08888600187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c1992505050565b6128c957600080fd5b6040805160208082018b9052600160a060020a03881682840152825180830384018152606090920190925280519101208761290382613968565b1461290d57600080fd5b60008981526009602052604090208054600160a060020a0319163317905586612959576000898152600e602090815260408083206001845290915290208054600160a060020a03191690555b60008981526008602052604090205461297c90600160a060020a0316878b613185565b50505060009586525050601160205250506040822080549290555090565b600160a060020a039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a653031373030310292840192909252909160029182168214612a6d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c5460a060020a900460ff1615612a8557600080fd5b8883612a918282611ad8565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d0281525090612b025760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060008b8152601260209081526040918290206001015482518084019093526006835260d160020a6518181b98181b029183019190915215612b885760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060008b8152600e6020908152604080832083805282528083208054600160a060020a031916600160a060020a038d161790558d8352600f82528083208d9055600d82529091208a514292612be19291908d0190613e42565b506013546040805160e060020a6387159d9b028152600481018f9052600160a060020a038981166024830152915191909216916387159d9b91604480830192600092919082900301818387803b158015612c3a57600080fd5b505af1158015612c4e573d6000803e3d6000fd5b505050508615612c8c5760008c8152600e602090815260408083206001845290915290208054600160a060020a031916600160a060020a038b161790555b612c94613eb0565b604051806060016040528088600160a060020a031681526020018381526020018a815250905080601260008f815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010155604082015181600201559050507f0166db8152debe7d1cfed1b1e12a32a28a986839ab44dff49682be23e29704de8d8d8d8d8d8d88604051808881526020018781526020018060200186600160a060020a0316600160a060020a0316815260200185815260200184151515158152602001838152602001828103825287818151815260200191508051906020019080838360005b83811015612db1578181015183820152602001612d99565b50505050905090810190601f168015612dde5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390a15050506000998a5250506011602052505060409095205495945050505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314612e8e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50604080518082019091526006815260d160020a6518189c181819026020820152600160a060020a038216612f075760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600c54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c8054600160a060020a031916600160a060020a0392909216919091179055565b600c5460a060020a900460ff1615612f7b57600080fd5b6000828152601260205260409020548290600160a060020a03163314612fa057600080fd5b600083815260106020908152604091829020805460ff19168515159081179091558251868152918201528151600080516020613f35833981519152929181900390910190a1505050565b6000908152600e6020908152604080832060018452909152902054600160a060020a0316151590565b6003805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156130995780601f1061306e57610100808354040283529160200191613099565b820191906000526020600020905b81548152906001019060200180831161307c57829003601f168201915b505050505081565b600081516041146130b457506000611540565b60208201516040830151606084015160001a6fa2a8918ca85bafe22016d0b997e4df6060ff60020a038211156130f05760009350505050611540565b8060ff16601b1415801561310857508060ff16601c14155b156131195760009350505050611540565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa158015613170573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6014546040805160e160020a6372331c73028152600160a060020a0386811660048301528581166024830152604482018590529151919092169163e46638e69160648083019260209291908290030181600087803b1580156131e657600080fd5b505af11580156131fa573d6000803e3d6000fd5b505050506040513d602081101561321057600080fd5b505161321b57600080fd5b6132268383836139b9565b6013546040805160e060020a6387159d9b02815260048101849052600160a060020a038681166024830152915191909216916387159d9b91604480830192600092919082900301818387803b15801561327e57600080fd5b505af1158015613292573d6000803e3d6000fd5b50505050505050565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a0383166133135760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b18181b0291830191909152600160a060020a03161561339f5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b5060008181526008602090815260408083208054600160a060020a031916600160a060020a038716908117909155808452600683528184208054600181810183559186528486208101879055868652600785528386205560048054918201908190557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b8201879055600590945282852055905191928492600080516020613f75833981519152908290a4505050565b8051613461906003906020840190613e42565b5050565b61347783600160a060020a0316613dbe565b156135f35760405160e160020a630a85bd01028082523360048301818152600160a060020a0388811660248601526044850187905260806064860190815286516084870152865194959189169463150b7a0294938b938a938a93909160a40190602085019080838360005b838110156134fa5781810151838201526020016134e2565b50505050905090810190601f1680156135275780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561354957600080fd5b505af115801561355d573d6000803e3d6000fd5b505050506040513d602081101561357357600080fd5b5051604080518082019091526006815260d060020a6530303630303502602082015291600160e060020a0319909116146135f15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b505b6135fe848484613185565b50505050565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a031690816136905760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600082815260096020526040902054600160a060020a0316156136cb5760008281526009602052604090208054600160a060020a03191690555b600160a060020a0381166000908152600660205260409020546136ea57fe5b600082815260076020908152604080832054600160a060020a038516845260069092528220549091600019909101908183146137a357600160a060020a038416600090815260066020526040902080548390811061374457fe5b90600052602060002001549050806006600086600160a060020a0316600160a060020a03168152602001908152602001600020848154811061378257fe5b60009182526020808320909101929092558281526007909152604090208390555b60008581526008602090815260408083208054600160a060020a031916905560078252808320839055600160a060020a0387168352600690915290208054906137f0906000198301613eda565b506004546137fa57fe5b60008581526005602052604090205460048054600019810194508490811061381e57fe5b90600052602060002001549150816004828154811061383957fe5b6000918252602090912001556004805490613858906000198301613eda565b5060008281526005602052604080822083905587825280822082905551879190600160a060020a03881690600080516020613f75833981519152908390a4505050505050565b6060816138c65750604080518082019091526001815260fc60020a6003026020820152610c14565b8160005b81156138de57600101600a820491506138ca565b6060816040519080825280601f01601f19166020018201604052801561390b576020820181803883390190505b50859350905060001982015b831561395f57600a840660300160f860020a028282806001900393508151811061393d57fe5b6020010190600160f860020a031916908160001a905350600a84049350613917565b50949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038416613a315760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a03858116911614613ac15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038316613b3a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600160a060020a038316331480613b685750600081815260096020526040902054600160a060020a031633145b80613b965750600160a060020a0383166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d260020a650c0c0d8c0c0d0281525090613c075760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610d7a578181015183820152602001610d62565b50600081815260096020526040902054600160a060020a031615613c425760008181526009602052604090208054600160a060020a03191690555b600160a060020a038316600090815260066020526040902054613c6157fe5b600081815260076020908152604080832054600160a060020a038716845260069092529091205460001901808214613d1557600160a060020a0385166000908152600660205260408120805483908110613cb757fe5b90600052602060002001549050806006600088600160a060020a0316600160a060020a031681526020019081526020016000208481548110613cf557fe5b600091825260208083209091019290925591825260079052604090208290555b600160a060020a0385166000908152600660205260409020805490613d3e906000198301613eda565b5060008381526008602090815260408083208054600160a060020a031916600160a060020a038981169182179092558085526006845282852080546001810180835591875285872081018a9055898752600790955283862094909455915192938793918a1691600080516020613f758339815191529190a4505050505050565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613e055782800160ff19823516178555613e32565b82800160010185558215613e32579182015b82811115613e32578235825591602001919060010190613e17565b50613e3e929150613efa565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613e8357805160ff1916838001178555613e32565b82800160010185558215613e32579182015b82811115613e32578251825591602001919060010190613e95565b60405180606001604052806000600160a060020a0316815260200160008152602001600081525090565b81548183558181111561127c5760008381526020902061127c9181019083015b61111f91905b80821115613e3e5760008155600101613f0056feb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb9651106eb2a6b59bafdf7d5d15a5fe2681abd76406ddf85d0af873cd23c221014dc3211cd3c497c4ee51feb1ed7bbb2d072b8c18bce7bbf0cf03d310a12b4afcd9818ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820c32f070ed85d3f9edcab8129a948a3f68141137c3295d1133ed892061068a2e10029