false
false
POA Network merged with the Gnosis Chain. More information about the merger.

Contract Address Details

0x363574E6C5C71c343d7348093D84320c76d5Dd29

Token
Arianee Smart-Asset (AriaSA)
Creator
0x860847–43debe at 0x95cad2–a3b03d
Balance
0 POA ( )
Tokens
Fetching tokens...
Transactions
389,909 Transactions
Transfers
0 Transfers
Gas Used
19,617,919,273
Last Balance Update
31971019
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
ArianeeSmartAsset




Optimization enabled
true
Compiler version
v0.5.6+commit.b259423e




Verified at
2019-06-25T08:28:43.835782Z

Constructor Arguments

000000000000000000000000d3eee7f8e8021db24825c3457d5479f2b57f40ef

Arg [0] (address) : <a href=/poa/core/address/0xd3eee7f8e8021db24825c3457d5479f2b57f40ef>0xd3eee7f8e8021db24825c3457d5479f2b57f40ef</a>

              

Contract source code

Sol2uml
new
// File: @0xcert/ethereum-utils-contracts/src/contracts/math/safe-math.sol

pragma solidity 0.5.6;

/**
 * @dev Math operations with safety checks that throw on error. This contract is based on the
 * source code at:
 * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol.
 */
library SafeMath
{

  /**
   * @dev Error constants.
   */
  string constant OVERFLOW = "008001";
  string constant SUBTRAHEND_GREATER_THEN_MINUEND = "008002";
  string constant DIVISION_BY_ZERO = "008003";

  /**
   * @dev Multiplies two numbers, reverts on overflow.
   * @param _factor1 Factor number.
   * @param _factor2 Factor number.
   * @return The product of the two factors.
   */
  function mul(
    uint256 _factor1,
    uint256 _factor2
  )
    internal
    pure
    returns (uint256 product)
  {
    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (_factor1 == 0)
    {
      return 0;
    }

    product = _factor1 * _factor2;
    require(product / _factor1 == _factor2, OVERFLOW);
  }

  /**
   * @dev Integer division of two numbers, truncating the quotient, reverts on division by zero.
   * @param _dividend Dividend number.
   * @param _divisor Divisor number.
   * @return The quotient.
   */
  function div(
    uint256 _dividend,
    uint256 _divisor
  )
    internal
    pure
    returns (uint256 quotient)
  {
    // Solidity automatically asserts when dividing by 0, using all gas.
    require(_divisor > 0, DIVISION_BY_ZERO);
    quotient = _dividend / _divisor;
    // assert(_dividend == _divisor * quotient + _dividend % _divisor); // There is no case in which this doesn't hold.
  }

  /**
   * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
   * @param _minuend Minuend number.
   * @param _subtrahend Subtrahend number.
   * @return Difference.
   */
  function sub(
    uint256 _minuend,
    uint256 _subtrahend
  )
    internal
    pure
    returns (uint256 difference)
  {
    require(_subtrahend <= _minuend, SUBTRAHEND_GREATER_THEN_MINUEND);
    difference = _minuend - _subtrahend;
  }

  /**
   * @dev Adds two numbers, reverts on overflow.
   * @param _addend1 Number.
   * @param _addend2 Number.
   * @return Sum.
   */
  function add(
    uint256 _addend1,
    uint256 _addend2
  )
    internal
    pure
    returns (uint256 sum)
  {
    sum = _addend1 + _addend2;
    require(sum >= _addend1, OVERFLOW);
  }

  /**
    * @dev Divides two numbers and returns the remainder (unsigned integer modulo), reverts when
    * dividing by zero.
    * @param _dividend Number.
    * @param _divisor Number.
    * @return Remainder.
    */
  function mod(
    uint256 _dividend,
    uint256 _divisor
  )
    internal
    pure
    returns (uint256 remainder)
  {
    require(_divisor != 0, DIVISION_BY_ZERO);
    remainder = _dividend % _divisor;
  }

}

// File: @0xcert/ethereum-utils-contracts/src/contracts/permission/abilitable.sol

pragma solidity 0.5.6;


/**
 * @title Contract for setting abilities.
 * @dev For optimization purposes the abilities are represented as a bitfield. Maximum number of
 * abilities is therefore 256. This is an example(for simplicity is made for max 8 abilities) of how
 * this works.
 * 00000001 Ability A - number representation 1
 * 00000010 Ability B - number representation 2
 * 00000100 Ability C - number representation 4
 * 00001000 Ability D - number representation 8
 * 00010000 Ability E - number representation 16
 * etc ...
 * To grant abilities B and C, we would need a bitfield of 00000110 which is represented by number
 * 6, in other words, the sum of abilities B and C. The same concept works for revoking abilities
 * and checking if someone has multiple abilities.
 */
contract Abilitable
{
  using SafeMath for uint;

  /**
   * @dev Error constants.
   */
  string constant NOT_AUTHORIZED = "017001";
  string constant CANNOT_REVOKE_OWN_SUPER_ABILITY = "017002";
  string constant INVALID_INPUT = "017003";

  /**
   * @dev Ability 1 (00000001) is a reserved ability called super ability. It is an
   * ability to grant or revoke abilities of other accounts. Other abilities are determined by the
   * implementing contract.
   */
  uint8 constant SUPER_ABILITY = 1;

  /**
   * @dev Maps address to ability ids.
   */
  mapping(address => uint256) public addressToAbility;

  /**
   * @dev Emits when an address is granted an ability.
   * @param _target Address to which we are granting abilities.
   * @param _abilities Number representing bitfield of abilities we are granting.
   */
  event GrantAbilities(
    address indexed _target,
    uint256 indexed _abilities
  );

  /**
   * @dev Emits when an address gets an ability revoked.
   * @param _target Address of which we are revoking an ability.
   * @param _abilities Number representing bitfield of abilities we are revoking.
   */
  event RevokeAbilities(
    address indexed _target,
    uint256 indexed _abilities
  );

  /**
   * @dev Guarantees that msg.sender has certain abilities.
   */
  modifier hasAbilities(
    uint256 _abilities
  )
  {
    require(_abilities > 0, INVALID_INPUT);
    require(
      addressToAbility[msg.sender] & _abilities == _abilities,
      NOT_AUTHORIZED
    );
    _;
  }

  /**
   * @dev Contract constructor.
   * Sets SUPER_ABILITY ability to the sender account.
   */
  constructor()
    public
  {
    addressToAbility[msg.sender] = SUPER_ABILITY;
    emit GrantAbilities(msg.sender, SUPER_ABILITY);
  }

  /**
   * @dev Grants specific abilities to specified address.
   * @param _target Address to grant abilities to.
   * @param _abilities Number representing bitfield of abilities we are granting.
   */
  function grantAbilities(
    address _target,
    uint256 _abilities
  )
    external
    hasAbilities(SUPER_ABILITY)
  {
    addressToAbility[_target] |= _abilities;
    emit GrantAbilities(_target, _abilities);
  }

  /**
   * @dev Unassigns specific abilities from specified address.
   * @param _target Address of which we revoke abilites.
   * @param _abilities Number representing bitfield of abilities we are revoking.
   * @param _allowSuperRevoke Additional check that prevents you from removing your own super
   * ability by mistake.
   */
  function revokeAbilities(
    address _target,
    uint256 _abilities,
    bool _allowSuperRevoke
  )
    external
    hasAbilities(SUPER_ABILITY)
  {
    if (!_allowSuperRevoke && msg.sender == _target)
    {
      require((_abilities & 1) == 0, CANNOT_REVOKE_OWN_SUPER_ABILITY);
    }
    addressToAbility[_target] &= ~_abilities;
    emit RevokeAbilities(_target, _abilities);
  }

  /**
   * @dev Check if an address has a specific ability. Throws if checking for 0.
   * @param _target Address for which we want to check if it has a specific abilities.
   * @param _abilities Number representing bitfield of abilities we are checking.
   */
  function isAble(
    address _target,
    uint256 _abilities
  )
    external
    view
    returns (bool)
  {
    require(_abilities > 0, INVALID_INPUT);
    return (addressToAbility[_target] & _abilities) == _abilities;
  }

}

// File: @0xcert/ethereum-utils-contracts/src/contracts/permission/ownable.sol

pragma solidity 0.5.6;

/**
 * @dev The contract has an owner address, and provides basic authorization control whitch
 * simplifies the implementation of user permissions. This contract is based on the source code at:
 * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Ownable.sol
 */
contract Ownable
{

  /**
   * @dev Error constants.
   */
  string constant NOT_OWNER = "018001";
  string constant ZERO_ADDRESS = "018002";

  /**
   * @dev Address of the owner.
   */
  address public owner;

  /**
   * @dev An event which is triggered when the owner is changed.
   * @param previousOwner The address of the previous owner.
   * @param newOwner The address of the new owner.
   */
  event OwnershipTransferred(
    address indexed previousOwner,
    address indexed newOwner
  );

  /**
   * @dev The constructor sets the original `owner` of the contract to the sender account.
   */
  constructor()
    public
  {
    owner = msg.sender;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner()
  {
    require(msg.sender == owner, NOT_OWNER);
    _;
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param _newOwner The address to transfer ownership to.
   */
  function transferOwnership(
    address _newOwner
  )
    public
    onlyOwner
  {
    require(_newOwner != address(0), ZERO_ADDRESS);
    emit OwnershipTransferred(owner, _newOwner);
    owner = _newOwner;
  }

}

// File: contracts/Pausable.sol

pragma solidity 0.5.6;

/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is Ownable {
    event Pause();
    event Unpause();

    bool public paused = false;

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     */
    modifier whenNotPaused() {
        require(!paused);
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     */
    modifier whenPaused() {
        require(paused);
        _;
    }

    /**
     * @dev called by the owner to pause, triggers stopped state
     */
    function pause() onlyOwner whenNotPaused public {
        paused = true;
        emit Pause();
    }

    /**
     * @dev called by the owner to unpause, returns to normal state
     */
    function unpause() onlyOwner whenPaused public {
        paused = false;
        emit Unpause();
    }
}

// File: contracts/ECDSA.sol

pragma solidity 0.5.6;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * (.note) This call _does not revert_ if the signature is invalid, or
     * if the signer is otherwise unable to be retrieved. In those scenarios,
     * the zero address is returned.
     *
     * (.warning) `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise)
     * be too long), and then calling `toEthSignedMessageHash` on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Check the signature length
        if (signature.length != 65) {
            return (address(0));
        }

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return address(0);
        }

        if (v != 27 && v != 28) {
            return address(0);
        }

        // If the signature is valid (and not malleable), return the signer address
        return ecrecover(hash, v, r, s);
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * replicates the behavior of the
     * [`eth_sign`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign)
     * JSON-RPC method.
     *
     * See `recover`.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }
}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721.sol

pragma solidity 0.5.6;

/**
 * @dev ERC-721 non-fungible token standard.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721
{

  /**
   * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are
   * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any
   * number of NFTs may be created and assigned without emitting Transfer. At the time of any
   * transfer, the approved address for that NFT (if any) is reset to none.
   */
  event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero
   * address indicates there is no approved address. When a Transfer event emits, this also
   * indicates that the approved address for that NFT (if any) is reset to none.
   */
  event Approval(
    address indexed _owner,
    address indexed _approved,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage
   * all NFTs of the owner.
   */
  event ApprovalForAll(
    address indexed _owner,
    address indexed _operator,
    bool _approved
  );

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the
   * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is
   * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this
   * function checks if `_to` is a smart contract (code size > 0). If so, it calls
   * `onERC721Received` on `_to` and throws if the return value is not
   * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes calldata _data
  )
    external;

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice This works identically to the other function with an extra data parameter, except this
   * function just sets data to ""
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
   * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero
   * address. Throws if `_tokenId` is not a valid NFT.
   * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
   * they mayb be permanently lost.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Set or reaffirm the approved address for an NFT.
   * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
   * the current NFT owner, or an authorized operator of the current owner.
   * @param _approved The new approved NFT controller.
   * @param _tokenId The NFT to approve.
   */
  function approve(
    address _approved,
    uint256 _tokenId
  )
    external;

  /**
   * @dev Enables or disables approval for a third party ("operator") to manage all of
   * `msg.sender`'s assets. It also emits the ApprovalForAll event.
   * @notice The contract MUST allow multiple operators per owner.
   * @param _operator Address to add to the set of authorized operators.
   * @param _approved True if the operators is approved, false to revoke approval.
   */
  function setApprovalForAll(
    address _operator,
    bool _approved
  )
    external;

  /**
   * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
   * considered invalid, and this function throws for queries about the zero address.
   * @param _owner Address for whom to query the balance.
   * @return Balance of _owner.
   */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint256);

  /**
   * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
   * invalid, and queries about them do throw.
   * @param _tokenId The identifier for an NFT.
   * @return Address of _tokenId owner.
   */
  function ownerOf(
    uint256 _tokenId
  )
    external
    view
    returns (address);

  /**
   * @dev Get the approved address for a single NFT.
   * @notice Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId The NFT to find the approved address for.
   * @return Address that _tokenId is approved for.
   */
  function getApproved(
    uint256 _tokenId
  )
    external
    view
    returns (address);

  /**
   * @dev Returns true if `_operator` is an approved operator for `_owner`, false otherwise.
   * @param _owner The address that owns the NFTs.
   * @param _operator The address that acts on behalf of the owner.
   * @return True if approved for all, false otherwise.
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  )
    external
    view
    returns (bool);

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-metadata.sol

pragma solidity 0.5.6;

/**
 * @dev Optional metadata extension for ERC-721 non-fungible token standard.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721Metadata
{

  /**
   * @dev Returns a descriptive name for a collection of NFTs in this contract.
   * @return Representing name.
   */
  function name()
    external
    view
    returns (string memory _name);

  /**
   * @dev Returns a abbreviated name for a collection of NFTs in this contract.
   * @return Representing symbol.
   */
  function symbol()
    external
    view
    returns (string memory _symbol);

  /**
   * @dev Returns a distinct Uniform Resource Identifier (URI) for a given asset. It Throws if
   * `_tokenId` is not a valid NFT. URIs are defined in RFC3986. The URI may point to a JSON file
   * that conforms to the "ERC721 Metadata JSON Schema".
   * @return URI of _tokenId.
   */
  function tokenURI(uint256 _tokenId)
    external
    view
    returns (string memory);

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-enumerable.sol

pragma solidity 0.5.6;

/**
 * @dev Optional enumeration extension for ERC-721 non-fungible token standard.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721Enumerable
{

  /**
   * @dev Returns a count of valid NFTs tracked by this contract, where each one of them has an
   * assigned and queryable owner not equal to the zero address.
   * @return Total supply of NFTs.
   */
  function totalSupply()
    external
    view
    returns (uint256);

  /**
   * @dev Returns the token identifier for the `_index`th NFT. Sort order is not specified.
   * @param _index A counter less than `totalSupply()`.
   * @return Token id.
   */
  function tokenByIndex(
    uint256 _index
  )
    external
    view
    returns (uint256);

  /**
   * @dev Returns the token identifier for the `_index`th NFT assigned to `_owner`. Sort order is
   * not specified. It throws if `_index` >= `balanceOf(_owner)` or if `_owner` is the zero address,
   * representing invalid NFTs.
   * @param _owner An address where we are interested in NFTs owned by them.
   * @param _index A counter less than `balanceOf(_owner)`.
   * @return Token id.
   */
  function tokenOfOwnerByIndex(
    address _owner,
    uint256 _index
  )
    external
    view
    returns (uint256);

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/erc721-token-receiver.sol

pragma solidity 0.5.6;

/**
 * @dev ERC-721 interface for accepting safe transfers.
 * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
 */
interface ERC721TokenReceiver
{

  /**
   * @dev Handle the receipt of a NFT. The ERC721 smart contract calls this function on the
   * recipient after a `transfer`. This function MAY throw to revert and reject the transfer. Return
   * of other than the magic value MUST result in the transaction being reverted.
   * Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` unless throwing.
   * @notice The contract address is always the message sender. A wallet/broker/auction application
   * MUST implement the wallet interface if it will accept safe transfers.
   * @param _operator The address which called `safeTransferFrom` function.
   * @param _from The address which previously owned the token.
   * @param _tokenId The NFT identifier which is being transferred.
   * @param _data Additional data with no specified format.
   * @return Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
   */
  function onERC721Received(
    address _operator,
    address _from,
    uint256 _tokenId,
    bytes calldata _data
  )
    external
    returns(bytes4);

}

// File: @0xcert/ethereum-utils-contracts/src/contracts/utils/erc165.sol

pragma solidity 0.5.6;

/**
 * @dev A standard for detecting smart contract interfaces.
 * See: https://eips.ethereum.org/EIPS/eip-165.
 */
interface ERC165
{

  /**
   * @dev Checks if the smart contract implements a specific interface.
   * @notice This function uses less than 30,000 gas.
   * @param _interfaceID The interface identifier, as specified in ERC-165.
   */
  function supportsInterface(
    bytes4 _interfaceID
  )
    external
    view
    returns (bool);

}

// File: @0xcert/ethereum-utils-contracts/src/contracts/utils/supports-interface.sol

pragma solidity 0.5.6;


/**
 * @dev Implementation of standard to publish supported interfaces.
 */
contract SupportsInterface is
  ERC165
{

  /**
   * @dev Mapping of supported intefraces.
   * @notice You must not set element 0xffffffff to true.
   */
  mapping(bytes4 => bool) internal supportedInterfaces;

  /**
   * @dev Contract constructor.
   */
  constructor()
    public
  {
    supportedInterfaces[0x01ffc9a7] = true; // ERC165
  }

  /**
   * @dev Function to check which interfaces are suported by this contract.
   * @param _interfaceID Id of the interface.
   */
  function supportsInterface(
    bytes4 _interfaceID
  )
    external
    view
    returns (bool)
  {
    return supportedInterfaces[_interfaceID];
  }

}

// File: @0xcert/ethereum-utils-contracts/src/contracts/utils/address-utils.sol

pragma solidity 0.5.6;

/**
 * @dev Utility library of inline functions on addresses.
 */
library AddressUtils
{

  /**
   * @dev Returns whether the target address is a contract.
   * @param _addr Address to check.
   * @return True if _addr is a contract, false if not.
   */
  function isContract(
    address _addr
  )
    internal
    view
    returns (bool addressCheck)
  {
    uint256 size;

    /**
     * XXX Currently there is no better way to check if there is a contract in an address than to
     * check the size of the code at that address.
     * See https://ethereum.stackexchange.com/a/14016/36603 for more details about how this works.
     * TODO: Check this again before the Serenity release, because all addresses will be
     * contracts then.
     */
    assembly { size := extcodesize(_addr) } // solhint-disable-line
    addressCheck = size > 0;
  }

}

// File: @0xcert/ethereum-erc721-contracts/src/contracts/nf-token-metadata-enumerable.sol

pragma solidity 0.5.6;








/**
 * @dev Optional metadata enumerable implementation for ERC-721 non-fungible token standard.
 */
contract NFTokenMetadataEnumerable is
  ERC721,
  ERC721Metadata,
  ERC721Enumerable,
  SupportsInterface
{
  using SafeMath for uint256;
  using AddressUtils for address;

  /**
   * @dev Error constants.
   */
  string constant ZERO_ADDRESS = "006001";
  string constant NOT_VALID_NFT = "006002";
  string constant NOT_OWNER_OR_OPERATOR = "006003";
  string constant NOT_OWNER_APPROWED_OR_OPERATOR = "006004";
  string constant NOT_ABLE_TO_RECEIVE_NFT = "006005";
  string constant NFT_ALREADY_EXISTS = "006006";
  string constant INVALID_INDEX = "006007";

  /**
   * @dev Magic value of a smart contract that can recieve NFT.
   * Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")).
   */
  bytes4 constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;

  /**
   * @dev A descriptive name for a collection of NFTs.
   */
  string internal nftName;

  /**
   * @dev An abbreviated name for NFTs.
   */
  string internal nftSymbol;

  /**
   * @dev URI base for NFT metadata. NFT URI is made from base + NFT id.
   */
  string public uriBase;

  /**
   * @dev Array of all NFT IDs.
   */
  uint256[] internal tokens;

  /**
   * @dev Mapping from token ID its index in global tokens array.
   */
  mapping(uint256 => uint256) internal idToIndex;

  /**
   * @dev Mapping from owner to list of owned NFT IDs.
   */
  mapping(address => uint256[]) internal ownerToIds;

  /**
   * @dev Mapping from NFT ID to its index in the owner tokens list.
   */
  mapping(uint256 => uint256) internal idToOwnerIndex;

  /**
   * @dev A mapping from NFT ID to the address that owns it.
   */
  mapping (uint256 => address) internal idToOwner;

  /**
   * @dev Mapping from NFT ID to approved address.
   */
  mapping (uint256 => address) internal idToApproval;

  /**
   * @dev Mapping from owner address to mapping of operator addresses.
   */
  mapping (address => mapping (address => bool)) internal ownerToOperators;

  /**
   * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are
   * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any
   * number of NFTs may be created and assigned without emitting Transfer. At the time of any
   * transfer, the approved address for that NFT (if any) is reset to none.
   * @param _from Sender of NFT (if address is zero address it indicates token creation).
   * @param _to Receiver of NFT (if address is zero address it indicates token destruction).
   * @param _tokenId The NFT that got transfered.
   */
  event Transfer(
    address indexed _from,
    address indexed _to,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero
   * address indicates there is no approved address. When a Transfer event emits, this also
   * indicates that the approved address for that NFT (if any) is reset to none.
   * @param _owner Owner of NFT.
   * @param _approved Address that we are approving.
   * @param _tokenId NFT which we are approving.
   */
  event Approval(
    address indexed _owner,
    address indexed _approved,
    uint256 indexed _tokenId
  );

  /**
   * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage
   * all NFTs of the owner.
   * @param _owner Owner of NFT.
   * @param _operator Address to which we are setting operator rights.
   * @param _approved Status of operator rights(true if operator rights are given and false if
   * revoked).
   */
  event ApprovalForAll(
    address indexed _owner,
    address indexed _operator,
    bool _approved
  );

  /**
   * @dev Contract constructor.
   * @notice When implementing this contract don't forget to set nftName, nftSymbol and uriBase.
   */
  constructor()
    public
  {
    supportedInterfaces[0x80ac58cd] = true; // ERC721
    supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata
    supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable
  }

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the
   * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is
   * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this
   * function checks if `_to` is a smart contract (code size > 0). If so, it calls
   * `onERC721Received` on `_to` and throws if the return value is not
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes calldata _data
  )
    external
  {
    _safeTransferFrom(_from, _to, _tokenId, _data);
  }

  /**
   * @dev Transfers the ownership of an NFT from one address to another address.
   * @notice This works identically to the other function with an extra data parameter, except this
   * function just sets data to "".
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external
  {
    _safeTransferFrom(_from, _to, _tokenId, "");
  }

  /**
   * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
   * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero
   * address. Throws if `_tokenId` is not a valid NFT.
   * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
   * they maybe be permanently lost.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    external
  {
    _transferFrom(_from, _to, _tokenId);
  }

  /**
   * @dev Set or reaffirm the approved address for an NFT.
   * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
   * the current NFT owner, or an authorized operator of the current owner.
   * @param _approved Address to be approved for the given NFT ID.
   * @param _tokenId ID of the token to be approved.
   */
  function approve(
    address _approved,
    uint256 _tokenId
  )
    external
  {
    // can operate
    address tokenOwner = idToOwner[_tokenId];
    require(
      tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender],
      NOT_OWNER_OR_OPERATOR
    );

    idToApproval[_tokenId] = _approved;
    emit Approval(tokenOwner, _approved, _tokenId);
  }

  /**
   * @dev Enables or disables approval for a third party ("operator") to manage all of
   * `msg.sender`'s assets. It also emits the ApprovalForAll event.
   * @notice This works even if sender doesn't own any tokens at the time.
   * @param _operator Address to add to the set of authorized operators.
   * @param _approved True if the operators is approved, false to revoke approval.
   */
  function setApprovalForAll(
    address _operator,
    bool _approved
  )
    external
  {
    ownerToOperators[msg.sender][_operator] = _approved;
    emit ApprovalForAll(msg.sender, _operator, _approved);
  }

  /**
   * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
   * considered invalid, and this function throws for queries about the zero address.
   * @param _owner Address for whom to query the balance.
   * @return Balance of _owner.
   */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint256)
  {
    require(_owner != address(0), ZERO_ADDRESS);
    return ownerToIds[_owner].length;
  }

  /**
   * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
   * invalid, and queries about them do throw.
   * @param _tokenId The identifier for an NFT.
   * @return Address of _tokenId owner.
   */
  function ownerOf(
    uint256 _tokenId
  )
    external
    view
    returns (address _owner)
  {
    _owner = idToOwner[_tokenId];
    require(_owner != address(0), NOT_VALID_NFT);
  }

  /**
   * @dev Get the approved address for a single NFT.
   * @notice Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId ID of the NFT to query the approval of.
   * @return Address that _tokenId is approved for.
   */
  function getApproved(
    uint256 _tokenId
  )
    external
    view
    returns (address)
  {
    require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
    return idToApproval[_tokenId];
  }

  /**
   * @dev Checks if `_operator` is an approved operator for `_owner`.
   * @param _owner The address that owns the NFTs.
   * @param _operator The address that acts on behalf of the owner.
   * @return True if approved for all, false otherwise.
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  )
    external
    view
    returns (bool)
  {
    return ownerToOperators[_owner][_operator];
  }

  /**
   * @dev Returns the count of all existing NFTs.
   * @return Total supply of NFTs.
   */
  function totalSupply()
    external
    view
    returns (uint256)
  {
    return tokens.length;
  }

  /**
   * @dev Returns NFT ID by its index.
   * @param _index A counter less than `totalSupply()`.
   * @return Token id.
   */
  function tokenByIndex(
    uint256 _index
  )
    external
    view
    returns (uint256)
  {
    require(_index < tokens.length, INVALID_INDEX);
    return tokens[_index];
  }

  /**
   * @dev returns the n-th NFT ID from a list of owner's tokens.
   * @param _owner Token owner's address.
   * @param _index Index number representing n-th token in owner's list of tokens.
   * @return Token id.
   */
  function tokenOfOwnerByIndex(
    address _owner,
    uint256 _index
  )
    external
    view
    returns (uint256)
  {
    require(_index < ownerToIds[_owner].length, INVALID_INDEX);
    return ownerToIds[_owner][_index];
  }

  /**
   * @dev Returns a descriptive name for a collection of NFTs.
   * @return Representing name.
   */
  function name()
    external
    view
    returns (string memory _name)
  {
    _name = nftName;
  }

  /**
   * @dev Returns an abbreviated name for NFTs.
   * @return Representing symbol.
   */
  function symbol()
    external
    view
    returns (string memory _symbol)
  {
    _symbol = nftSymbol;
  }

  /**
   * @notice A distinct Uniform Resource Identifier (URI) for a given asset.
   * @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC 3986. The URI may point
   * to a JSON file that conforms to the "ERC721 Metadata JSON Schema".
   * @param _tokenId Id for which we want URI.
   * @return URI of _tokenId.
   */
  function tokenURI(
    uint256 _tokenId
  )
    external
    view
    returns (string memory)
  {
    require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
    if (bytes(uriBase).length > 0)
    {
      return string(abi.encodePacked(uriBase, _uint2str(_tokenId)));
    }
    return "";
  }

  /**
   * @dev Set a distinct URI (RFC 3986) base for all nfts.
   * @notice this is a internal function which should be called from user-implemented external
   * function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _uriBase String representing RFC 3986 URI base.
   */
  function _setUriBase(
    string memory _uriBase
  )
    internal
  {
    uriBase = _uriBase;
  }

  /**
   * @dev Creates a new NFT.
   * @notice This is a private function which should be called from user-implemented external
   * function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _to The address that will own the created NFT.
   * @param _tokenId of the NFT to be created by the msg.sender.
   */
  function _create(
    address _to,
    uint256 _tokenId
  )
    internal
  {
    require(_to != address(0), ZERO_ADDRESS);
    require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);

    // add NFT
    idToOwner[_tokenId] = _to;

    uint256 length = ownerToIds[_to].push(_tokenId);
    idToOwnerIndex[_tokenId] = length - 1;

    // add to tokens array
    length = tokens.push(_tokenId);
    idToIndex[_tokenId] = length - 1;

    emit Transfer(address(0), _to, _tokenId);
  }

  /**
   * @dev Destroys a NFT.
   * @notice This is a private function which should be called from user-implemented external
   * destroy function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _tokenId ID of the NFT to be destroyed.
   */
  function _destroy(
    uint256 _tokenId
  )
    internal
  {
    // valid NFT
    address _owner = idToOwner[_tokenId];
    require(_owner != address(0), NOT_VALID_NFT);

    // clear approval
    if (idToApproval[_tokenId] != address(0))
    {
      delete idToApproval[_tokenId];
    }

    // remove NFT
    assert(ownerToIds[_owner].length > 0);

    uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
    uint256 lastTokenIndex = ownerToIds[_owner].length - 1;
    uint256 lastToken;
    if (lastTokenIndex != tokenToRemoveIndex)
    {
      lastToken = ownerToIds[_owner][lastTokenIndex];
      ownerToIds[_owner][tokenToRemoveIndex] = lastToken;
      idToOwnerIndex[lastToken] = tokenToRemoveIndex;
    }

    delete idToOwner[_tokenId];
    delete idToOwnerIndex[_tokenId];
    ownerToIds[_owner].length--;

    // remove from tokens array
    assert(tokens.length > 0);

    uint256 tokenIndex = idToIndex[_tokenId];
    lastTokenIndex = tokens.length - 1;
    lastToken = tokens[lastTokenIndex];

    tokens[tokenIndex] = lastToken;

    tokens.length--;
    // Consider adding a conditional check for the last token in order to save GAS.
    idToIndex[lastToken] = tokenIndex;
    idToIndex[_tokenId] = 0;

    emit Transfer(_owner, address(0), _tokenId);
  }

  /**
   * @dev Helper methods that actually does the transfer.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function _transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    internal
  {
    // valid NFT
    require(_from != address(0), ZERO_ADDRESS);
    require(idToOwner[_tokenId] == _from, NOT_VALID_NFT);
    require(_to != address(0), ZERO_ADDRESS);

    // can transfer
    require(
      _from == msg.sender
      || idToApproval[_tokenId] == msg.sender
      || ownerToOperators[_from][msg.sender],
      NOT_OWNER_APPROWED_OR_OPERATOR
    );

    // clear approval
    if (idToApproval[_tokenId] != address(0))
    {
      delete idToApproval[_tokenId];
    }

    // remove NFT
    assert(ownerToIds[_from].length > 0);

    uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
    uint256 lastTokenIndex = ownerToIds[_from].length - 1;

    if (lastTokenIndex != tokenToRemoveIndex)
    {
      uint256 lastToken = ownerToIds[_from][lastTokenIndex];
      ownerToIds[_from][tokenToRemoveIndex] = lastToken;
      idToOwnerIndex[lastToken] = tokenToRemoveIndex;
    }

    ownerToIds[_from].length--;

    // add NFT
    idToOwner[_tokenId] = _to;
    uint256 length = ownerToIds[_to].push(_tokenId);
    idToOwnerIndex[_tokenId] = length - 1;

    emit Transfer(_from, _to, _tokenId);
  }

  /**
   * @dev Helper function that actually does the safeTransfer.
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   * @param _data Additional data with no specified format, sent in call to `_to`.
   */
  function _safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes memory _data
  )
    internal
  {
    if (_to.isContract())
    {
      require(
        ERC721TokenReceiver(_to)
          .onERC721Received(msg.sender, _from, _tokenId, _data) == MAGIC_ON_ERC721_RECEIVED,
        NOT_ABLE_TO_RECEIVE_NFT
      );
    }

    _transferFrom(_from, _to, _tokenId);
  }

  /**
   * @dev Helper function that changes uint to string representation.
   * @return String representation.
   */
  function _uint2str(
    uint256 _i
  )
    internal
    pure
    returns (string memory str)
  {
    if (_i == 0)
    {
      return "0";
    }
    uint256 j = _i;
    uint256 length;
    while (j != 0)
    {
      length++;
      j /= 10;
    }
    bytes memory bstr = new bytes(length);
    uint256 k = length - 1;
    j = _i;
    while (j != 0)
    {
      bstr[k--] = byte(uint8(48 + j % 10));
      j /= 10;
    }
    str = string(bstr);
  }

}

// File: contracts/ArianeeSmartAsset.sol

pragma solidity 0.5.6;

contract ArianeeWhitelist {
  function addWhitelistedAddress(uint256 _tokenId, address _address) external;
}


contract ArianeeStore{
    function canTransfer(address _to,address _from,uint256 _tokenId) external returns(bool);
    function canDestroy(uint256 _tokenId, address _sender) external returns(bool);
}






/// @title Contract handling Arianee Certificates.
contract ArianeeSmartAsset is
NFTokenMetadataEnumerable,
Abilitable,
Ownable,
Pausable
{

  /**
   * @dev Mapping from token id to URI.
   */
  mapping(uint256 => string) internal idToUri;

  /**
   * @dev Mapping from token id to Token Access (0=view, 1=transfer).
   */
  mapping(uint256 => mapping(uint256 => address)) internal tokenAccess;

  /**
   * @dev Mapping from token id to TokenImprintUpdate.
   */
  mapping(uint256 => bytes32) internal idToImprint;

  /**
   * @dev Mapping from token id to recovery request bool.
   */
  mapping(uint256=>bool) internal recoveryRequest;

  /**
   * @dev Mapping from token id to total rewards for this NFT.
   */
  mapping(uint256=>uint256) internal rewards;

  /**
   * @dev Mapping from token id to Cert.
   */
  mapping(uint256 => Cert) internal certificate;

  /**
   * @dev This emits when a new address is set.
   */
  event SetAddress(string _addressType, address _newAddress);

  struct Cert {
      address tokenIssuer;
      uint256 tokenCreationDate;
      uint256 tokenRecoveryTimestamp;
  }

  /**
   * @dev Ability to create and hydrate NFT.
   */
  uint8 constant ABILITY_CREATE_ASSET = 2;

  /**
   * @dev Error constants.
   */
  string constant CAPABILITY_NOT_SUPPORTED = "007001";
  string constant TRANSFERS_DISABLED = "007002";
  string constant NOT_VALID_CERT = "007003";
  string constant NFT_ALREADY_SET = "007006";
  string constant NOT_OPERATOR = "007004";

  /**
   * Interface for all the connected contracts.
   */
  ArianeeWhitelist public arianeeWhitelist;
  ArianeeStore public store;

  /**
   * @dev This emits when a token is hydrated.
   */
  event Hydrated(uint256 _tokenId, bytes32 _imprint, string _uri, address _initialKey, uint256 _tokenRecoveryTimestamp, bool _initialKeyIsRequestKey, uint256 _tokenCreation);

  /**
   * @dev This emits when a issuer request a NFT recovery.
   */
  event RecoveryRequestUpdated(uint256 _tokenId, bool _active);

  /**
   * @dev This emits when a NFT is recovered to the issuer.
   */
  event TokenRecovered(uint256 _token);

  /**
   * @dev This emits when a NFT's URI is udpated.
   */
  event TokenURIUpdated(uint256 _tokenId, string URI);

  /**
   * @dev This emits when a token access is added.
   */
  event TokenAccessAdded(uint256 _tokenId, address _encryptedTokenKey, bool _enable, uint256 _tokenType);

  /**
   * @dev This emits when a token access is destroyed.
   */
  event TokenDestroyed(uint256 _tokenId);

  /**
   * @dev This emits when the uri base is udpated.
   */
  event SetNewUriBase(string _newUriBase);


  /**
   * @dev Check if the msg.sender can operate the NFT.
   * @param _tokenId ID of the NFT to test.
   * @param _operator Address to test.
   */
  modifier isOperator(uint256 _tokenId, address _operator) {
    require(canOperate(_tokenId, _operator), NOT_OPERATOR);
    _;
  }

  /**
   * @dev Check if msg.sender is the issuer of a NFT.
   * @param _tokenId ID of the NFT to test.
   */
   modifier isIssuer(uint256 _tokenId) {
    require(msg.sender == certificate[_tokenId].tokenIssuer);
    _;
   }

  /**
    * @dev Initialize this contract. Acts as a constructor
    * @param _arianeeWhitelistAddress Adress of the whitelist contract.
    */
  constructor(
    address _arianeeWhitelistAddress
  )
  public
  {
    nftName = "Arianee Smart-Asset";
    nftSymbol = "AriaSA";
    setWhitelistAddress(_arianeeWhitelistAddress);
    _setUriBase("https://cert.arianee.org/");
  }

  /**
   * @notice Change address of the store infrastructure.
   * @param _storeAddress new address of the store.
   */
  function setStoreAddress(address _storeAddress) external onlyOwner(){
    store = ArianeeStore(address(_storeAddress));
    emit SetAddress("storeAddress", _storeAddress);
  }

  /**
   * @notice Reserve a NFT at the given ID.
   * @dev Has to be called through an authorized contract.
   * @dev Can only be called by an authorized address.
   * @param _tokenId ID to reserve.
   * @param _to receiver of the token.
   * @param _rewards total rewards of this NFT.
   */
  function reserveToken(uint256 _tokenId, address _to, uint256 _rewards) external hasAbilities(ABILITY_CREATE_ASSET) whenNotPaused() {
    super._create(_to, _tokenId);
    rewards[_tokenId] = _rewards;
  }

  /**
   * @notice Recover the NFT to the issuer.
   * @dev only if called by the issuer and if called before the token Recovery Timestamp of the NFT.
   * @param _tokenId ID of the NFT to recover.
   */
  function recoverTokenToIssuer(uint256 _tokenId) external whenNotPaused() isIssuer(_tokenId) {
    require(block.timestamp < certificate[_tokenId].tokenRecoveryTimestamp);
    idToApproval[_tokenId] = certificate[_tokenId].tokenIssuer;
    _transferFrom(idToOwner[_tokenId], certificate[_tokenId].tokenIssuer, _tokenId);

    emit TokenRecovered(_tokenId);
  }

  /**
   * @notice Update a recovery request (doesn't transfer the NFT).
   * @dev Works only if called by the issuer.
   * @param _tokenId ID of the NFT to recover.
   * @param _active boolean to active or unactive the request.
   */
  function updateRecoveryRequest(uint256 _tokenId, bool _active) external whenNotPaused() isIssuer(_tokenId){
    recoveryRequest[_tokenId] = _active;

    emit RecoveryRequestUpdated(_tokenId, _active);
  }

  /**
   * @notice Valid a recovery request and transfer the NFT to the issuer.
   * @dev only if the request is active and if called by the owner of the contract.
   * @param _tokenId Id of the NFT to recover.
   */
  function validRecoveryRequest(uint256 _tokenId) external onlyOwner(){
    require(recoveryRequest[_tokenId]);
    recoveryRequest[_tokenId] = false;

    idToApproval[_tokenId] = owner;
    _transferFrom(idToOwner[_tokenId], certificate[_tokenId].tokenIssuer, _tokenId);

    emit RecoveryRequestUpdated(_tokenId, false);
    emit TokenRecovered(_tokenId);
  }

  /**
   * @notice External function to update the tokenURI.
   * @notice Can only be called by the NFT's issuer.
   * @param _tokenId ID of the NFT to edit.
   * @param _uri New URI for the certificate.
   */
  function updateTokenURI(uint256 _tokenId, string calldata _uri) external isIssuer(_tokenId) whenNotPaused() {
    require(idToOwner[_tokenId] != address(0), NOT_VALID_CERT);
    idToUri[_tokenId] = _uri;

    emit TokenURIUpdated(_tokenId, _uri);
  }

  /**
   * @notice Add a token access to a NFT.
   * @notice can only be called by an NFT's operator.
   * @param _tokenId ID of the NFT.
   * @param _key Public address of the token to encode the hash with.
   * @param _enable Enable or disable the token access.
   * @param _tokenType Type of token access (0=view, 1=tranfer).
   * @return true.
   */
  function addTokenAccess(uint256 _tokenId, address _key, bool _enable, uint256 _tokenType) external isOperator(_tokenId, msg.sender) whenNotPaused() {
      require(_tokenType>0);
    if (_enable) {
      tokenAccess[_tokenId][_tokenType] = _key;
    }
    else {
      tokenAccess[_tokenId][_tokenType] = address(0);
    }

    emit TokenAccessAdded(_tokenId, _key, _enable, _tokenType);
  }

  /**
   * @notice Transfers the ownership of a NFT to another address
   * @notice Requires to send the correct tokenKey and the NFT has to be requestable
   * @dev Has to be called through an authorized contract.
   * @dev approve the requester if _tokenKey is valid to allow transferFrom without removing ERC721 compliance.
   * @param _tokenId ID of the NFT to transfer.
   * @param _hash Hash of tokenId + newOwner address.
   * @param _keepRequestToken If false erase the access token of the NFT.
   * @param _newOwner Address of the new owner of the NFT.
   * @return total rewards of this NFT.
   */
  function requestToken(uint256 _tokenId, bytes32 _hash, bool _keepRequestToken, address _newOwner, bytes calldata _signature) external hasAbilities(ABILITY_CREATE_ASSET) whenNotPaused() returns(uint256 reward){

    require(isTokenValid(_tokenId, _hash, 1, _signature));
    bytes32 message = keccak256(abi.encode(_tokenId, _newOwner));
    require(ECDSA.toEthSignedMessageHash(message) == _hash);

    idToApproval[_tokenId] = msg.sender;

    if(!_keepRequestToken){
      tokenAccess[_tokenId][1] = address(0);
    }
    _transferFrom(idToOwner[_tokenId], _newOwner, _tokenId);
    reward = rewards[_tokenId];
    delete rewards[_tokenId];
  }

  /**
   * @notice Destroy a token.
   * @notice Can only be called by the issuer.
   * @param _tokenId to destroy.
   */
  function destroy(uint256 _tokenId) external whenNotPaused() {
    require(store.canDestroy(_tokenId, msg.sender));

    _destroy(_tokenId);
    idToImprint[_tokenId] = "";
    idToUri[_tokenId] = "";
    tokenAccess[_tokenId][0] = address(0);
    tokenAccess[_tokenId][1] = address(0);
    rewards[_tokenId] = 0;
    Cert memory _emptyCert = Cert({
             tokenIssuer : address(0),
             tokenCreationDate: 0,
             tokenRecoveryTimestamp: 0
            });

    certificate[_tokenId] = _emptyCert;

    emit TokenDestroyed(_tokenId);
  }

  /**
   * @notice return the URI of a NFT.
   * @param _tokenId uint256 ID of the NFT.
   * @return URI of the NFT.
   */
  function tokenURI(uint256 _tokenId) external view returns (string memory){
      require(idToOwner[_tokenId] != address(0), NOT_VALID_CERT);
      if(bytes(idToUri[_tokenId]).length > 0){
        return idToUri[_tokenId];
      }
      else{
          return string(abi.encodePacked(uriBase, _uint2str(_tokenId)));
      }
  }

  /**
   * @notice Check if a token is requestable.
   * @param _tokenId uint256 ID of the token to check.
   * @return True if the NFT is requestable.
   */
  function isRequestable(uint256 _tokenId) external view returns (bool) {
    return tokenAccess[_tokenId][1] != address(0);
  }

  /**
   * @notice The issuer address for a given Token ID.
   * @dev Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId Id for which we want the issuer.
   * @return Issuer address of _tokenId.
   */
  function issuerOf(uint256 _tokenId) external view returns(address _tokenIssuer){
      require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
      _tokenIssuer = certificate[_tokenId].tokenIssuer;
  }

   /**
   * @notice The imprint for a given Token ID.
   * @dev Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId Id for which we want the imprint.
   * @return Imprint address of _tokenId.
   */
  function tokenImprint(uint256 _tokenId) external view returns(bytes32 _imprint){
      require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
      _imprint = idToImprint[_tokenId];
  }


  /**
   * @notice The creation date for a given Token ID.
   * @dev Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId Id for which we want the creation date.
   * @return Creation date of _tokenId.
   */
  function tokenCreation(uint256 _tokenId) external view returns(uint256 _tokenCreation){
      require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
      _tokenCreation = certificate[_tokenId].tokenCreationDate;
  }

  /**
   * @notice The Token Access for a given Token ID and token type.
   * @dev Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId Id for which we want the token access.
   * @param _tokenType for which we want the token access.
   * @return Token access of _tokenId.
   */
  function tokenHashedAccess(uint256 _tokenId, uint256 _tokenType) external view returns(address _tokenAccess){
      require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
      _tokenAccess = tokenAccess[_tokenId][_tokenType];
  }

  /**
   * @notice The recovery timestamp for a given Token ID.
   * @dev Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId Id for which we want the recovery timestamp.
   * @return Recovery timestamp of _tokenId.
   */
  function tokenRecoveryDate(uint256 _tokenId) external view returns(uint256 _tokenRecoveryTimestamp){
      require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
      _tokenRecoveryTimestamp = certificate[_tokenId].tokenRecoveryTimestamp;
  }

  /**
   * @notice The recovery timestamp for a given Token ID.
   * @dev Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId Id for which we want the recovery timestamp.
   * @return Recovery timestamp of _tokenId.
   */
  function recoveryRequestOpen(uint256 _tokenId) external view returns(bool _recoveryRequest){
      require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
      _recoveryRequest = recoveryRequest[_tokenId];
  }

  /**
   * @notice The rewards for a given Token ID.
   * @param _tokenId Id for which we want the rewards.
   * @return Rewards of _tokenId.
   */
  function getRewards(uint256 _tokenId) external view returns(uint256){
      return rewards[_tokenId];
  }

  /**
   * @notice Check if an operator is valid for a given NFT.
   * @param _tokenId nft to check.
   * @param _operator operator to check.
   * @return true if operator is valid.
   */
  function canOperate(uint256 _tokenId, address _operator) public view returns (bool){
    address tokenOwner = idToOwner[_tokenId];
    return tokenOwner == _operator || ownerToOperators[tokenOwner][_operator];
  }

  /**
   * @notice Change the base URI address.
   * @param _newURIBase the new URI base address.
   */
  function setUriBase(string memory _newURIBase) public onlyOwner(){
      _setUriBase(_newURIBase);
      emit SetNewUriBase(_newURIBase);
  }

  /**
   * @notice Change address of the whitelist.
   * @param _whitelistAddres new address of the whitelist.
   */
  function setWhitelistAddress(address _whitelistAddres) public onlyOwner(){
    arianeeWhitelist = ArianeeWhitelist(address(_whitelistAddres));
    emit SetAddress("whitelistAddress", _whitelistAddres);
  }

  /**
   * @notice Specify information on a reserved NFT.
   * @dev to be called through an authorized contract.
   * @dev Can only be called once and by an NFT's operator.
   * @param _tokenId ID of the NFT to modify.
   * @param _imprint Proof of the certification.
   * @param _uri URI of the JSON certification.
   * @param _initialKey Initial key.
   * @param _tokenRecoveryTimestamp Limit date for the issuer to be able to transfer back the NFT.
   * @param _initialKeyIsRequestKey If true set initial key as request key.
   */
  function hydrateToken(uint256 _tokenId, bytes32 _imprint, string memory _uri, address _initialKey, uint256 _tokenRecoveryTimestamp, bool _initialKeyIsRequestKey, address _owner) public hasAbilities(ABILITY_CREATE_ASSET) whenNotPaused() isOperator(_tokenId, _owner) returns(uint256){
    require(!(certificate[_tokenId].tokenCreationDate > 0), NFT_ALREADY_SET);
    uint256 _tokenCreation = block.timestamp;
    tokenAccess[_tokenId][0] = _initialKey;
    idToImprint[_tokenId] = _imprint;
    idToUri[_tokenId] = _uri;

    arianeeWhitelist.addWhitelistedAddress(_tokenId, _owner);

    if (_initialKeyIsRequestKey) {
      tokenAccess[_tokenId][1] = _initialKey;
    }

    Cert memory _cert = Cert({
             tokenIssuer : _owner,
             tokenCreationDate: _tokenCreation,
             tokenRecoveryTimestamp :_tokenRecoveryTimestamp
            });

    certificate[_tokenId] = _cert;

    emit Hydrated(_tokenId, _imprint, _uri, _initialKey, _tokenRecoveryTimestamp, _initialKeyIsRequestKey, _tokenCreation);

    return rewards[_tokenId];
  }

  /**
   * @notice Check if a token access is valid.
   * @param _tokenId ID of the NFT to validate.
   * @param _hash Hash of tokenId + newOwner address.
   * @param _tokenType Type of token access (0=view, 1=transfer).
   */
  function isTokenValid(uint256 _tokenId, bytes32 _hash, uint256 _tokenType, bytes memory _signature) public view returns (bool){
    return ECDSA.recover(_hash, _signature) ==  tokenAccess[_tokenId][_tokenType];
  }

  /**
   * @notice Legacy function of TransferFrom, add the new owner as whitelisted for the message.
   * @dev Require the store to approve the transfer.
   */
  function _transferFrom(address _to, address _from, uint256 _tokenId) internal {
    require(store.canTransfer(_to, _from, _tokenId));
    super._transferFrom(_to, _from, _tokenId);
    arianeeWhitelist.addWhitelistedAddress(_tokenId, _to);
  }

}
        

Contract ABI

[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"_interfaceID"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isTokenValid","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bytes32","name":"_hash"},{"type":"uint256","name":"_tokenType"},{"type":"bytes","name":"_signature"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"_name"}],"name":"name","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getApproved","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"approve","inputs":[{"type":"address","name":"_approved"},{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"grantAbilities","inputs":[{"type":"address","name":"_target"},{"type":"uint256","name":"_abilities"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"validRecoveryRequest","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"arianeeWhitelist","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalSupply","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateTokenURI","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"string","name":"_uri"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferFrom","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"reserveToken","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"address","name":"_to"},{"type":"uint256","name":"_rewards"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setUriBase","inputs":[{"type":"string","name":"_newURIBase"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"tokenOfOwnerByIndex","inputs":[{"type":"address","name":"_owner"},{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"unpause","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"addressToAbility","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"tokenByIndex","inputs":[{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"paused","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"_tokenCreation"}],"name":"tokenCreation","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"_owner"}],"name":"ownerOf","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"_recoveryRequest"}],"name":"recoveryRequestOpen","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setStoreAddress","inputs":[{"type":"address","name":"_storeAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"_imprint"}],"name":"tokenImprint","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"canOperate","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"address","name":"_operator"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"pause","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"_symbol"}],"name":"symbol","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"store","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"destroy","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setWhitelistAddress","inputs":[{"type":"address","name":"_whitelistAddres"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setApprovalForAll","inputs":[{"type":"address","name":"_operator"},{"type":"bool","name":"_approved"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"_tokenIssuer"}],"name":"issuerOf","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"revokeAbilities","inputs":[{"type":"address","name":"_target"},{"type":"uint256","name":"_abilities"},{"type":"bool","name":"_allowSuperRevoke"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"recoverTokenToIssuer","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addTokenAccess","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"address","name":"_key"},{"type":"bool","name":"_enable"},{"type":"uint256","name":"_tokenType"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"_tokenId"},{"type":"bytes","name":"_data"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isAble","inputs":[{"type":"address","name":"_target"},{"type":"uint256","name":"_abilities"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getRewards","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":""}],"name":"tokenURI","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"_tokenAccess"}],"name":"tokenHashedAccess","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"uint256","name":"_tokenType"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"_tokenRecoveryTimestamp"}],"name":"tokenRecoveryDate","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":"reward"}],"name":"requestToken","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bytes32","name":"_hash"},{"type":"bool","name":"_keepRequestToken"},{"type":"address","name":"_newOwner"},{"type":"bytes","name":"_signature"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isApprovedForAll","inputs":[{"type":"address","name":"_owner"},{"type":"address","name":"_operator"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"hydrateToken","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bytes32","name":"_imprint"},{"type":"string","name":"_uri"},{"type":"address","name":"_initialKey"},{"type":"uint256","name":"_tokenRecoveryTimestamp"},{"type":"bool","name":"_initialKeyIsRequestKey"},{"type":"address","name":"_owner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"_newOwner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateRecoveryRequest","inputs":[{"type":"uint256","name":"_tokenId"},{"type":"bool","name":"_active"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isRequestable","inputs":[{"type":"uint256","name":"_tokenId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":""}],"name":"uriBase","inputs":[],"constant":true},{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"address","name":"_arianeeWhitelistAddress"}]},{"type":"event","name":"SetAddress","inputs":[{"type":"string","name":"_addressType","indexed":false},{"type":"address","name":"_newAddress","indexed":false}],"anonymous":false},{"type":"event","name":"Hydrated","inputs":[{"type":"uint256","name":"_tokenId","indexed":false},{"type":"bytes32","name":"_imprint","indexed":false},{"type":"string","name":"_uri","indexed":false},{"type":"address","name":"_initialKey","indexed":false},{"type":"uint256","name":"_tokenRecoveryTimestamp","indexed":false},{"type":"bool","name":"_initialKeyIsRequestKey","indexed":false},{"type":"uint256","name":"_tokenCreation","indexed":false}],"anonymous":false},{"type":"event","name":"RecoveryRequestUpdated","inputs":[{"type":"uint256","name":"_tokenId","indexed":false},{"type":"bool","name":"_active","indexed":false}],"anonymous":false},{"type":"event","name":"TokenRecovered","inputs":[{"type":"uint256","name":"_token","indexed":false}],"anonymous":false},{"type":"event","name":"TokenURIUpdated","inputs":[{"type":"uint256","name":"_tokenId","indexed":false},{"type":"string","name":"URI","indexed":false}],"anonymous":false},{"type":"event","name":"TokenAccessAdded","inputs":[{"type":"uint256","name":"_tokenId","indexed":false},{"type":"address","name":"_encryptedTokenKey","indexed":false},{"type":"bool","name":"_enable","indexed":false},{"type":"uint256","name":"_tokenType","indexed":false}],"anonymous":false},{"type":"event","name":"TokenDestroyed","inputs":[{"type":"uint256","name":"_tokenId","indexed":false}],"anonymous":false},{"type":"event","name":"SetNewUriBase","inputs":[{"type":"string","name":"_newUriBase","indexed":false}],"anonymous":false},{"type":"event","name":"Pause","inputs":[],"anonymous":false},{"type":"event","name":"Unpause","inputs":[],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false},{"type":"event","name":"GrantAbilities","inputs":[{"type":"address","name":"_target","indexed":true},{"type":"uint256","name":"_abilities","indexed":true}],"anonymous":false},{"type":"event","name":"RevokeAbilities","inputs":[{"type":"address","name":"_target","indexed":true},{"type":"uint256","name":"_abilities","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"_from","indexed":true},{"type":"address","name":"_to","indexed":true},{"type":"uint256","name":"_tokenId","indexed":true}],"anonymous":false},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"_owner","indexed":true},{"type":"address","name":"_approved","indexed":true},{"type":"uint256","name":"_tokenId","indexed":true}],"anonymous":false},{"type":"event","name":"ApprovalForAll","inputs":[{"type":"address","name":"_owner","indexed":true},{"type":"address","name":"_operator","indexed":true},{"type":"bool","name":"_approved","indexed":false}],"anonymous":false}]
              

Contract Creation Code

0x6080604052600c805460a060020a60ff02191690553480156200002157600080fd5b5060405160208062004503833981018060405260208110156200004357600080fd5b50517f67be87c3ff9960ca1e9cfac5cab2ff4747269cf9ed20c9b7306235ac35a491c58054600160ff1991821681179092557ff7815fccbf112960a73756e185887fedcb9fc64ca0a16cc5923b7960ed78080080548216831790557f9562381dfbc2d8b8b66e765249f330164b73e329e5f01670660643571d1974df80548216831790557f77b7bbe0e49b76487c9476b5db3354cf5270619d0037ccb899c2a4c4a75b4318805490911682179055336000818152600b6020526040808220849055517fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f9190a3600c8054600160a060020a031916331790556040805180820190915260138082527f417269616e656520536d6172742d41737365740000000000000000000000000060209092019182526200018191600191620003be565b506040805180820190915260068082527f41726961534100000000000000000000000000000000000000000000000000006020909201918252620001c891600291620003be565b50620001dd8164010000000062000233810204565b6200022c6040518060400160405280601981526020017f68747470733a2f2f636572742e617269616e65652e6f72672f00000000000000815250620003a5640100000000026401000000009004565b5062000463565b600c5460408051808201909152600681527f3031383030310000000000000000000000000000000000000000000000000000602082015290600160a060020a031633146200031c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620002e0578181015183820152602001620002c6565b50505050905090810190601f1680156200030e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060138054600160a060020a038316600160a060020a031990911681179091556040805160208101929092528082526010828201527f77686974656c69737441646472657373000000000000000000000000000000006060830152517fb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb965119181900360800190a150565b8051620003ba906003906020840190620003be565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200040157805160ff191683800117855562000431565b8280016001018555821562000431579182015b828111156200043157825182559160200191906001019062000414565b506200043f92915062000443565b5090565b6200046091905b808211156200043f57600081556001016200044a565b90565b61409080620004736000396000f3fe608060405234801561001057600080fd5b50600436106102495760e060020a600035046301ffc9a7811461024e5780630657a5ea1461028957806306fdde0314610340578063081812fc146103bd578063095ea7b3146103f65780630ab319e8146104245780631332f1b814610450578063165ec2e21461046d57806318160ddd1461047557806318e97fd11461048f57806323b872dd146105045780632526c9331461053a57806327fc0cff1461056c5780632f745c59146106105780633f4ba83a1461063c57806342842e0e1461064457806345a32c861461067a5780634f6ccce7146106a05780635c975abb146106bd5780635facb882146106c55780636352211e146106e257806363ad2b6a146106ff5780636559e59a1461071c57806370a082311461074257806370c31afc1461076857806380a4edda146107855780638456cb59146107b15780638da5cb5b146107b957806395d89b41146107c1578063975057e7146107c95780639d118770146107d1578063a224c745146107ee578063a22cb46514610814578063a4e2ee1114610842578063aca910e71461085f578063b5aaa9d514610893578063b71c34d5146108b0578063b88d4fde146108ea578063ba00a33014610978578063c0d8012c146109a4578063c87b56dd146109c1578063cc55578e146109de578063dde5c1c714610a01578063e261ed7714610a1e578063e985e9c514610aaf578063ec046d0a14610add578063f2fde38b14610bac578063f3fd860514610bd2578063f421b0e914610bf7578063fbca0ce114610c14575b600080fd5b6102756004803603602081101561026457600080fd5b5035600160e060020a031916610c1c565b604080519115158252519081900360200190f35b6102756004803603608081101561029f57600080fd5b81359160208101359160408201359190810190608081016060820135602060020a8111156102cc57600080fd5b8201836020820111156102de57600080fd5b803590602001918460018302840111602060020a831117156102ff57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610c3f945050505050565b610348610c7f565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561038257818101518382015260200161036a565b50505050905090810190601f1680156103af5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103da600480360360208110156103d357600080fd5b5035610d14565b60408051600160a060020a039092168252519081900360200190f35b6104226004803603604081101561040c57600080fd5b50600160a060020a038135169060200135610df8565b005b6104226004803603604081101561043a57600080fd5b50600160a060020a038135169060200135610f0f565b6104226004803603602081101561046657600080fd5b5035610fff565b6103da611141565b61047d611150565b60408051918252519081900360200190f35b610422600480360360408110156104a557600080fd5b81359190810190604081016020820135602060020a8111156104c657600080fd5b8201836020820111156104d857600080fd5b803590602001918460018302840111602060020a831117156104f957600080fd5b509092509050611157565b6104226004803603606081101561051a57600080fd5b50600160a060020a038135811691602081013590911690604001356112a6565b6104226004803603606081101561055057600080fd5b50803590600160a060020a0360208201351690604001356112b6565b6104226004803603602081101561058257600080fd5b810190602081018135602060020a81111561059c57600080fd5b8201836020820111156105ae57600080fd5b803590602001918460018302840111602060020a831117156105cf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611393945050505050565b61047d6004803603604081101561062657600080fd5b50600160a060020a0381351690602001356114b6565b61042261157b565b6104226004803603606081101561065a57600080fd5b50600160a060020a0381358116916020810135909116906040013561164a565b61047d6004803603602081101561069057600080fd5b5035600160a060020a0316611665565b61047d600480360360208110156106b657600080fd5b5035611677565b61027561170d565b61047d600480360360208110156106db57600080fd5b503561171d565b6103da600480360360208110156106f857600080fd5b50356117be565b6102756004803603602081101561071557600080fd5b5035611850565b6104226004803603602081101561073257600080fd5b5035600160a060020a03166118f1565b61047d6004803603602081101561075857600080fd5b5035600160a060020a03166119d7565b61047d6004803603602081101561077e57600080fd5b5035611a6f565b6102756004803603604081101561079b57600080fd5b5080359060200135600160a060020a0316611b0d565b610422611b64565b6103da611c3a565b610348611c49565b6103da611ca7565b610422600480360360208110156107e757600080fd5b5035611cb6565b6104226004803603602081101561080457600080fd5b5035600160a060020a0316611e73565b6104226004803603604081101561082a57600080fd5b50600160a060020a0381351690602001351515611f5d565b6103da6004803603602081101561085857600080fd5b5035611fcb565b6104226004803603606081101561087557600080fd5b50600160a060020a0381351690602081013590604001351515612072565b610422600480360360208110156108a957600080fd5b50356121f4565b610422600480360360808110156108c657600080fd5b50803590600160a060020a03602082013516906040810135151590606001356122c4565b6104226004803603608081101561090057600080fd5b600160a060020a03823581169260208101359091169160408201359190810190608081016060820135602060020a81111561093a57600080fd5b82018360208201111561094c57600080fd5b803590602001918460018302840111602060020a8311171561096d57600080fd5b509092509050612423565b6102756004803603604081101561098e57600080fd5b50600160a060020a03813516906020013561246c565b61047d600480360360208110156109ba57600080fd5b5035612505565b610348600480360360208110156109d757600080fd5b5035612517565b6103da600480360360408110156109f457600080fd5b508035906020013561273d565b61047d60048036036020811015610a1757600080fd5b50356127ef565b61047d600480360360a0811015610a3457600080fd5b8135916020810135916040820135151591600160a060020a036060820135169181019060a081016080820135602060020a811115610a7157600080fd5b820183602082011115610a8357600080fd5b803590602001918460018302840111602060020a83111715610aa457600080fd5b509092509050612890565b61027560048036036040811015610ac557600080fd5b50600160a060020a0381358116916020013516612a6a565b61047d600480360360e0811015610af357600080fd5b813591602081013591810190606081016040820135602060020a811115610b1957600080fd5b820183602082011115610b2b57600080fd5b803590602001918460018302840111602060020a83111715610b4c57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050600160a060020a0383358116945060208401359360408101351515935060600135169050612a98565b61042260048036036020811015610bc257600080fd5b5035600160a060020a0316612ee1565b61042260048036036040811015610be857600080fd5b50803590602001351515613034565b61027560048036036020811015610c0d57600080fd5b50356130ba565b6103486130e3565b600160e060020a0319811660009081526020819052604090205460ff165b919050565b6000848152600e60209081526040808320858452909152812054600160a060020a0316610c6c8584613171565b600160a060020a03161495945050505050565b60018054604080516020601f60026000196101008789161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b820191906000526020600020905b815481529060010190602001808311610ced57829003601f168201915b5050505050905090565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316610ddb5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610da0578181015183820152602001610d88565b50505050905090810190601f168015610dcd5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050600090815260096020526040902054600160a060020a031690565b600081815260086020526040902054600160a060020a031633811480610e415750600160a060020a0381166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d060020a653030363030330281525090610eb25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000828152600960205260408082208054600160a060020a031916600160a060020a0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a6530313730303102918301919091526001919082168214610fb35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a0383166000818152600b6020526040808220805486179055518492917fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f91a3505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461107c5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008181526010602052604090205460ff1661109857600080fd5b6000818152601060209081526040808320805460ff19169055600c54600983528184208054600160a060020a031916600160a060020a03928316179055600883528184205460129093529220546110f492918216911683613255565b60408051828152600060208201528151600080516020614005833981519152929181900390910190a16040805182815290516000805160206140258339815191529181900360200190a150565b601354600160a060020a031681565b6004545b90565b6000838152601260205260409020548390600160a060020a0316331461117c57600080fd5b600c5460a060020a900460ff161561119357600080fd5b6000848152600860209081526040918290205482518084019093526006835260d060020a653030373030330291830191909152600160a060020a031661121d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000848152600d60205260409020611237908484613e94565b507f931f495b9a8e5d8e61946ea5d61e021f636cfe213a801f97589c18c152e408bd84848460405180848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a150505050565b6112b1838383613255565b505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a653031373030310291830191909152600291908216821461135a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561137257600080fd5b61137c838561336b565b506000928352601160205260409092209190915550565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146114105760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5061141a8161351e565b7f2f1172752b4c027870f0c890ad9d16d3a4d3af09c120988bd8620ef750b124aa816040518080602001828103825283818151815260200191508051906020019080838360005b83811015611479578181015183820152602001611461565b50505050905090810190601f1680156114a65780820380516001836020036101000a031916815260200191505b509250505060405180910390a150565b600160a060020a038216600090815260066020818152604080842054815180830190925292815260d060020a6530303630303702918101919091529083106115425760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a038316600090815260066020526040902080548390811061156757fe5b906000526020600020015490505b92915050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146115f85760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1661160f57600080fd5b600c805460a060020a60ff02191690556040517f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3390600090a1565b6112b183838360405180602001604052806000815250613535565b600b6020526000908152604090205481565b600454604080518082019091526006815260d060020a6530303630303702602082015260009183106116ed5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600482815481106116fb57fe5b90600052602060002001549050919050565b600c5460a060020a900460ff1681565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166117a75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526012602052604090206001015490565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a0316908161184a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50919050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166118da5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526010602052604090205460ff1690565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461196e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060148054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252600c8282015260a060020a6b73746f72654164647265737302606083015251600080516020613fe58339815191529181900360800190a150565b604080518082019091526006815260d060020a65303036303031026020820152600090600160a060020a038316611a525760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600160a060020a031660009081526006602052604090205490565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316611af95760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50506000908152600f602052604090205490565b600082815260086020526040812054600160a060020a03908116908316811480611b5c5750600160a060020a038082166000908152600a602090815260408083209387168352929052205460ff165b949350505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611be15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1615611bf957600080fd5b600c805460a060020a60ff02191660a060020a1790556040517f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62590600090a1565b600c54600160a060020a031681565b60028054604080516020601f6000196101006001871615020190941685900493840181900481028201810190925282815260609390929091830182828015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b601454600160a060020a031681565b600c5460a060020a900460ff1615611ccd57600080fd5b6014546040805160e060020a6382300d89028152600481018490523360248201529051600160a060020a03909216916382300d89916044808201926020929091908290030181600087803b158015611d2457600080fd5b505af1158015611d38573d6000803e3d6000fd5b505050506040513d6020811015611d4e57600080fd5b5051611d5957600080fd5b611d62816136d4565b6000818152600f602090815260408083208390558051808301808352848252858552600d90935292209151611d98929190613f12565b506000818152600e6020908152604080832083805282528083208054600160a060020a031990811690915560018452818420805490911690558383526011909152812055611de4613f80565b506040805160608101825260008082526020808301828152838501838152868452601283529285902084518154600160a060020a031916600160a060020a039091161781559051600182015591516002909201919091558251848152925191927fbc3b3ac51ba6ff17c341408a0d6270952ecdd0bbbd47586aecc338d73af9d78d929081900390910190a15050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611ef05760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060138054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252601082820152608060020a6f77686974656c6973744164647265737302606083015251600080516020613fe58339815191529181900360800190a150565b336000818152600a60209081526040808320600160a060020a03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166120555760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600090815260126020526040902054600160a060020a031690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a65303137303031029183019190915260019190821682146121165760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b508115801561212d575033600160a060020a038516145b156121a757604080518082019091526006815260d160020a6518189b98181902602082015260018416156121a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505b600160a060020a0384166000818152600b602052604080822080548719169055518592917fbb71944f65b9a48cc7d835179fb5e874f29b60aa0195785fb54968d8dddef08a91a350505050565b600c5460a060020a900460ff161561220b57600080fd5b6000818152601260205260409020548190600160a060020a0316331461223057600080fd5b600082815260126020526040902060020154421061224d57600080fd5b60008281526012602081815260408084208054600984528286208054600160a060020a031916600160a060020a0392831617905560088452919094205492909152915461229f92918216911684613255565b6040805183815290516000805160206140258339815191529181900360200190a15050565b83336122d08282611b0d565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d02815250906123415760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561235957600080fd5b6000831161236657600080fd5b83156123a3576000868152600e6020908152604080832086845290915290208054600160a060020a031916600160a060020a0387161790556123cb565b6000868152600e6020908152604080832086845290915290208054600160a060020a03191690555b60408051878152600160a060020a0387166020820152851515818301526060810185905290517fd4fada85986a6a990ebf8397071db3525f738377b4b8d4c3e9c8847dd7c7bd409181900360800190a1505050505050565b61246585858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061353592505050565b5050505050565b600080821160405180604001604052806006815260200160d060020a6530313730303302815250906124e25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600160a060020a03919091166000908152600b602052604090205481161490565b60009081526011602052604090205490565b6000818152600860209081526040918290205482518084019093526006835260d060020a65303037303033029183019190915260609190600160a060020a03166125a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000828152600d6020526040902054600260001961010060018416150201909116041561266c576000828152600d602090815260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845290918301828280156126605780601f1061263557610100808354040283529160200191612660565b820191906000526020600020905b81548152906001019060200180831161264357829003601f168201915b50505050509050610c3a565b60036126778361396e565b60405160200180838054600181600116156101000203166002900480156126d55780601f106126b35761010080835404028352918201916126d5565b820191906000526020600020905b8154815290600101906020018083116126c1575b5050825160208401908083835b602083106127015780518252601f1990920191602091820191016126e2565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529050610c3a565b60008281526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166127c75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50506000918252600e60209081526040808420928452919052902054600160a060020a031690565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166128795760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526012602052604090206002015490565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a6530313730303102928401929092529091600291821682146129355760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561294d57600080fd5b6129908888600187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3f92505050565b61299957600080fd5b6040805160208082018b9052600160a060020a0388168284015282518083038401815260609092019092528051910120876129d382613a38565b146129dd57600080fd5b60008981526009602052604090208054600160a060020a0319163317905586612a29576000898152600e602090815260408083206001845290915290208054600160a060020a03191690555b600089815260086020526040902054612a4c90600160a060020a0316878b613255565b50505060009586525050601160205250506040822080549290555090565b600160a060020a039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a653031373030310292840192909252909160029182168214612b3d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1615612b5557600080fd5b8883612b618282611b0d565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d0281525090612bd25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008b8152601260209081526040918290206001015482518084019093526006835260d160020a6518181b98181b029183019190915215612c585760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008b8152600e6020908152604080832083805282528083208054600160a060020a031916600160a060020a038d161790558d8352600f82528083208d9055600d82529091208a514292612cb19291908d0190613f12565b506013546040805160e060020a6387159d9b028152600481018f9052600160a060020a038981166024830152915191909216916387159d9b91604480830192600092919082900301818387803b158015612d0a57600080fd5b505af1158015612d1e573d6000803e3d6000fd5b505050508615612d5c5760008c8152600e602090815260408083206001845290915290208054600160a060020a031916600160a060020a038b161790555b612d64613f80565b604051806060016040528088600160a060020a031681526020018381526020018a815250905080601260008f815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010155604082015181600201559050507f0166db8152debe7d1cfed1b1e12a32a28a986839ab44dff49682be23e29704de8d8d8d8d8d8d88604051808881526020018781526020018060200186600160a060020a0316600160a060020a0316815260200185815260200184151515158152602001838152602001828103825287818151815260200191508051906020019080838360005b83811015612e81578181015183820152602001612e69565b50505050905090810190601f168015612eae5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390a15050506000998a5250506011602052505060409095205495945050505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314612f5e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50604080518082019091526006815260d160020a6518189c181819026020820152600160a060020a038216612fd75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c8054600160a060020a031916600160a060020a0392909216919091179055565b600c5460a060020a900460ff161561304b57600080fd5b6000828152601260205260409020548290600160a060020a0316331461307057600080fd5b600083815260106020908152604091829020805460ff19168515159081179091558251868152918201528151600080516020614005833981519152929181900390910190a1505050565b6000908152600e6020908152604080832060018452909152902054600160a060020a0316151590565b6003805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156131695780601f1061313e57610100808354040283529160200191613169565b820191906000526020600020905b81548152906001019060200180831161314c57829003601f168201915b505050505081565b6000815160411461318457506000611575565b60208201516040830151606084015160001a6fa2a8918ca85bafe22016d0b997e4df6060ff60020a038211156131c05760009350505050611575565b8060ff16601b141580156131d857508060ff16601c14155b156131e95760009350505050611575565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa158015613240573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6014546040805160e160020a6372331c73028152600160a060020a0386811660048301528581166024830152604482018590529151919092169163e46638e69160648083019260209291908290030181600087803b1580156132b657600080fd5b505af11580156132ca573d6000803e3d6000fd5b505050506040513d60208110156132e057600080fd5b50516132eb57600080fd5b6132f6838383613a89565b6013546040805160e060020a6387159d9b02815260048101849052600160a060020a038681166024830152915191909216916387159d9b91604480830192600092919082900301818387803b15801561334e57600080fd5b505af1158015613362573d6000803e3d6000fd5b50505050505050565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a0383166133e35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b18181b0291830191909152600160a060020a03161561346f5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008181526008602090815260408083208054600160a060020a031916600160a060020a038716908117909155808452600683528184208054600181810183559186528486208101879055868652600785528386205560048054918201908190557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b8201879055600590945282852055905191928492600080516020614045833981519152908290a4505050565b8051613531906003906020840190613f12565b5050565b61354783600160a060020a0316613e8e565b156136c35760405160e160020a630a85bd01028082523360048301818152600160a060020a0388811660248601526044850187905260806064860190815286516084870152865194959189169463150b7a0294938b938a938a93909160a40190602085019080838360005b838110156135ca5781810151838201526020016135b2565b50505050905090810190601f1680156135f75780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561361957600080fd5b505af115801561362d573d6000803e3d6000fd5b505050506040513d602081101561364357600080fd5b5051604080518082019091526006815260d060020a6530303630303502602082015291600160e060020a0319909116146136c15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505b6136ce848484613255565b50505050565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a031690816137605760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600082815260096020526040902054600160a060020a03161561379b5760008281526009602052604090208054600160a060020a03191690555b600160a060020a0381166000908152600660205260409020546137ba57fe5b600082815260076020908152604080832054600160a060020a0385168452600690925282205490916000199091019081831461387357600160a060020a038416600090815260066020526040902080548390811061381457fe5b90600052602060002001549050806006600086600160a060020a0316600160a060020a03168152602001908152602001600020848154811061385257fe5b60009182526020808320909101929092558281526007909152604090208390555b60008581526008602090815260408083208054600160a060020a031916905560078252808320839055600160a060020a0387168352600690915290208054906138c0906000198301613faa565b506004546138ca57fe5b6000858152600560205260409020546004805460001981019450849081106138ee57fe5b90600052602060002001549150816004828154811061390957fe5b6000918252602090912001556004805490613928906000198301613faa565b5060008281526005602052604080822083905587825280822082905551879190600160a060020a03881690600080516020614045833981519152908390a4505050505050565b6060816139965750604080518082019091526001815260fc60020a6003026020820152610c3a565b8160005b81156139ae57600101600a8204915061399a565b6060816040519080825280601f01601f1916602001820160405280156139db576020820181803883390190505b50859350905060001982015b8315613a2f57600a840660300160f860020a0282828060019003935081518110613a0d57fe5b6020010190600160f860020a031916908160001a905350600a840493506139e7565b50949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038416613b015760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a03858116911614613b915760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038316613c0a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a038316331480613c385750600081815260096020526040902054600160a060020a031633145b80613c665750600160a060020a0383166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d260020a650c0c0d8c0c0d0281525090613cd75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600081815260096020526040902054600160a060020a031615613d125760008181526009602052604090208054600160a060020a03191690555b600160a060020a038316600090815260066020526040902054613d3157fe5b600081815260076020908152604080832054600160a060020a038716845260069092529091205460001901808214613de557600160a060020a0385166000908152600660205260408120805483908110613d8757fe5b90600052602060002001549050806006600088600160a060020a0316600160a060020a031681526020019081526020016000208481548110613dc557fe5b600091825260208083209091019290925591825260079052604090208290555b600160a060020a0385166000908152600660205260409020805490613e0e906000198301613faa565b5060008381526008602090815260408083208054600160a060020a031916600160a060020a038981169182179092558085526006845282852080546001810180835591875285872081018a9055898752600790955283862094909455915192938793918a16916000805160206140458339815191529190a4505050505050565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613ed55782800160ff19823516178555613f02565b82800160010185558215613f02579182015b82811115613f02578235825591602001919060010190613ee7565b50613f0e929150613fca565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613f5357805160ff1916838001178555613f02565b82800160010185558215613f02579182015b82811115613f02578251825591602001919060010190613f65565b60405180606001604052806000600160a060020a0316815260200160008152602001600081525090565b8154818355818111156112b1576000838152602090206112b19181019083015b61115491905b80821115613f0e5760008155600101613fd056feb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb9651106eb2a6b59bafdf7d5d15a5fe2681abd76406ddf85d0af873cd23c221014dc3211cd3c497c4ee51feb1ed7bbb2d072b8c18bce7bbf0cf03d310a12b4afcd9818ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820e9896e5a1e3faba7c7f12686854a548c7a25f66710bc5a5f38be182b40660cd80029000000000000000000000000d3eee7f8e8021db24825c3457d5479f2b57f40ef

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102495760e060020a600035046301ffc9a7811461024e5780630657a5ea1461028957806306fdde0314610340578063081812fc146103bd578063095ea7b3146103f65780630ab319e8146104245780631332f1b814610450578063165ec2e21461046d57806318160ddd1461047557806318e97fd11461048f57806323b872dd146105045780632526c9331461053a57806327fc0cff1461056c5780632f745c59146106105780633f4ba83a1461063c57806342842e0e1461064457806345a32c861461067a5780634f6ccce7146106a05780635c975abb146106bd5780635facb882146106c55780636352211e146106e257806363ad2b6a146106ff5780636559e59a1461071c57806370a082311461074257806370c31afc1461076857806380a4edda146107855780638456cb59146107b15780638da5cb5b146107b957806395d89b41146107c1578063975057e7146107c95780639d118770146107d1578063a224c745146107ee578063a22cb46514610814578063a4e2ee1114610842578063aca910e71461085f578063b5aaa9d514610893578063b71c34d5146108b0578063b88d4fde146108ea578063ba00a33014610978578063c0d8012c146109a4578063c87b56dd146109c1578063cc55578e146109de578063dde5c1c714610a01578063e261ed7714610a1e578063e985e9c514610aaf578063ec046d0a14610add578063f2fde38b14610bac578063f3fd860514610bd2578063f421b0e914610bf7578063fbca0ce114610c14575b600080fd5b6102756004803603602081101561026457600080fd5b5035600160e060020a031916610c1c565b604080519115158252519081900360200190f35b6102756004803603608081101561029f57600080fd5b81359160208101359160408201359190810190608081016060820135602060020a8111156102cc57600080fd5b8201836020820111156102de57600080fd5b803590602001918460018302840111602060020a831117156102ff57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610c3f945050505050565b610348610c7f565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561038257818101518382015260200161036a565b50505050905090810190601f1680156103af5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103da600480360360208110156103d357600080fd5b5035610d14565b60408051600160a060020a039092168252519081900360200190f35b6104226004803603604081101561040c57600080fd5b50600160a060020a038135169060200135610df8565b005b6104226004803603604081101561043a57600080fd5b50600160a060020a038135169060200135610f0f565b6104226004803603602081101561046657600080fd5b5035610fff565b6103da611141565b61047d611150565b60408051918252519081900360200190f35b610422600480360360408110156104a557600080fd5b81359190810190604081016020820135602060020a8111156104c657600080fd5b8201836020820111156104d857600080fd5b803590602001918460018302840111602060020a831117156104f957600080fd5b509092509050611157565b6104226004803603606081101561051a57600080fd5b50600160a060020a038135811691602081013590911690604001356112a6565b6104226004803603606081101561055057600080fd5b50803590600160a060020a0360208201351690604001356112b6565b6104226004803603602081101561058257600080fd5b810190602081018135602060020a81111561059c57600080fd5b8201836020820111156105ae57600080fd5b803590602001918460018302840111602060020a831117156105cf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611393945050505050565b61047d6004803603604081101561062657600080fd5b50600160a060020a0381351690602001356114b6565b61042261157b565b6104226004803603606081101561065a57600080fd5b50600160a060020a0381358116916020810135909116906040013561164a565b61047d6004803603602081101561069057600080fd5b5035600160a060020a0316611665565b61047d600480360360208110156106b657600080fd5b5035611677565b61027561170d565b61047d600480360360208110156106db57600080fd5b503561171d565b6103da600480360360208110156106f857600080fd5b50356117be565b6102756004803603602081101561071557600080fd5b5035611850565b6104226004803603602081101561073257600080fd5b5035600160a060020a03166118f1565b61047d6004803603602081101561075857600080fd5b5035600160a060020a03166119d7565b61047d6004803603602081101561077e57600080fd5b5035611a6f565b6102756004803603604081101561079b57600080fd5b5080359060200135600160a060020a0316611b0d565b610422611b64565b6103da611c3a565b610348611c49565b6103da611ca7565b610422600480360360208110156107e757600080fd5b5035611cb6565b6104226004803603602081101561080457600080fd5b5035600160a060020a0316611e73565b6104226004803603604081101561082a57600080fd5b50600160a060020a0381351690602001351515611f5d565b6103da6004803603602081101561085857600080fd5b5035611fcb565b6104226004803603606081101561087557600080fd5b50600160a060020a0381351690602081013590604001351515612072565b610422600480360360208110156108a957600080fd5b50356121f4565b610422600480360360808110156108c657600080fd5b50803590600160a060020a03602082013516906040810135151590606001356122c4565b6104226004803603608081101561090057600080fd5b600160a060020a03823581169260208101359091169160408201359190810190608081016060820135602060020a81111561093a57600080fd5b82018360208201111561094c57600080fd5b803590602001918460018302840111602060020a8311171561096d57600080fd5b509092509050612423565b6102756004803603604081101561098e57600080fd5b50600160a060020a03813516906020013561246c565b61047d600480360360208110156109ba57600080fd5b5035612505565b610348600480360360208110156109d757600080fd5b5035612517565b6103da600480360360408110156109f457600080fd5b508035906020013561273d565b61047d60048036036020811015610a1757600080fd5b50356127ef565b61047d600480360360a0811015610a3457600080fd5b8135916020810135916040820135151591600160a060020a036060820135169181019060a081016080820135602060020a811115610a7157600080fd5b820183602082011115610a8357600080fd5b803590602001918460018302840111602060020a83111715610aa457600080fd5b509092509050612890565b61027560048036036040811015610ac557600080fd5b50600160a060020a0381358116916020013516612a6a565b61047d600480360360e0811015610af357600080fd5b813591602081013591810190606081016040820135602060020a811115610b1957600080fd5b820183602082011115610b2b57600080fd5b803590602001918460018302840111602060020a83111715610b4c57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050600160a060020a0383358116945060208401359360408101351515935060600135169050612a98565b61042260048036036020811015610bc257600080fd5b5035600160a060020a0316612ee1565b61042260048036036040811015610be857600080fd5b50803590602001351515613034565b61027560048036036020811015610c0d57600080fd5b50356130ba565b6103486130e3565b600160e060020a0319811660009081526020819052604090205460ff165b919050565b6000848152600e60209081526040808320858452909152812054600160a060020a0316610c6c8584613171565b600160a060020a03161495945050505050565b60018054604080516020601f60026000196101008789161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b820191906000526020600020905b815481529060010190602001808311610ced57829003601f168201915b5050505050905090565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316610ddb5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610da0578181015183820152602001610d88565b50505050905090810190601f168015610dcd5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050600090815260096020526040902054600160a060020a031690565b600081815260086020526040902054600160a060020a031633811480610e415750600160a060020a0381166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d060020a653030363030330281525090610eb25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000828152600960205260408082208054600160a060020a031916600160a060020a0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a6530313730303102918301919091526001919082168214610fb35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a0383166000818152600b6020526040808220805486179055518492917fc4adfc5f00262a1ab9b2241c7e98408a91e58dc5777d786164bba34a7652f62f91a3505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461107c5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008181526010602052604090205460ff1661109857600080fd5b6000818152601060209081526040808320805460ff19169055600c54600983528184208054600160a060020a031916600160a060020a03928316179055600883528184205460129093529220546110f492918216911683613255565b60408051828152600060208201528151600080516020614005833981519152929181900390910190a16040805182815290516000805160206140258339815191529181900360200190a150565b601354600160a060020a031681565b6004545b90565b6000838152601260205260409020548390600160a060020a0316331461117c57600080fd5b600c5460a060020a900460ff161561119357600080fd5b6000848152600860209081526040918290205482518084019093526006835260d060020a653030373030330291830191909152600160a060020a031661121d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000848152600d60205260409020611237908484613e94565b507f931f495b9a8e5d8e61946ea5d61e021f636cfe213a801f97589c18c152e408bd84848460405180848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a150505050565b6112b1838383613255565b505050565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a653031373030310291830191909152600291908216821461135a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561137257600080fd5b61137c838561336b565b506000928352601160205260409092209190915550565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146114105760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5061141a8161351e565b7f2f1172752b4c027870f0c890ad9d16d3a4d3af09c120988bd8620ef750b124aa816040518080602001828103825283818151815260200191508051906020019080838360005b83811015611479578181015183820152602001611461565b50505050905090810190601f1680156114a65780820380516001836020036101000a031916815260200191505b509250505060405180910390a150565b600160a060020a038216600090815260066020818152604080842054815180830190925292815260d060020a6530303630303702918101919091529083106115425760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a038316600090815260066020526040902080548390811061156757fe5b906000526020600020015490505b92915050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a031633146115f85760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1661160f57600080fd5b600c805460a060020a60ff02191690556040517f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3390600090a1565b6112b183838360405180602001604052806000815250613535565b600b6020526000908152604090205481565b600454604080518082019091526006815260d060020a6530303630303702602082015260009183106116ed5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600482815481106116fb57fe5b90600052602060002001549050919050565b600c5460a060020a900460ff1681565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166117a75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526012602052604090206001015490565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a0316908161184a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50919050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166118da5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526010602052604090205460ff1690565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a0316331461196e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060148054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252600c8282015260a060020a6b73746f72654164647265737302606083015251600080516020613fe58339815191529181900360800190a150565b604080518082019091526006815260d060020a65303036303031026020820152600090600160a060020a038316611a525760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600160a060020a031660009081526006602052604090205490565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a0316611af95760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50506000908152600f602052604090205490565b600082815260086020526040812054600160a060020a03908116908316811480611b5c5750600160a060020a038082166000908152600a602090815260408083209387168352929052205460ff165b949350505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611be15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1615611bf957600080fd5b600c805460a060020a60ff02191660a060020a1790556040517f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62590600090a1565b600c54600160a060020a031681565b60028054604080516020601f6000196101006001871615020190941685900493840181900481028201810190925282815260609390929091830182828015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b601454600160a060020a031681565b600c5460a060020a900460ff1615611ccd57600080fd5b6014546040805160e060020a6382300d89028152600481018490523360248201529051600160a060020a03909216916382300d89916044808201926020929091908290030181600087803b158015611d2457600080fd5b505af1158015611d38573d6000803e3d6000fd5b505050506040513d6020811015611d4e57600080fd5b5051611d5957600080fd5b611d62816136d4565b6000818152600f602090815260408083208390558051808301808352848252858552600d90935292209151611d98929190613f12565b506000818152600e6020908152604080832083805282528083208054600160a060020a031990811690915560018452818420805490911690558383526011909152812055611de4613f80565b506040805160608101825260008082526020808301828152838501838152868452601283529285902084518154600160a060020a031916600160a060020a039091161781559051600182015591516002909201919091558251848152925191927fbc3b3ac51ba6ff17c341408a0d6270952ecdd0bbbd47586aecc338d73af9d78d929081900390910190a15050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314611ef05760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060138054600160a060020a038316600160a060020a03199091168117909155604080516020810192909252808252601082820152608060020a6f77686974656c6973744164647265737302606083015251600080516020613fe58339815191529181900360800190a150565b336000818152600a60209081526040808320600160a060020a03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166120555760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600090815260126020526040902054600160a060020a031690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283902054835180850190945290835260d060020a65303137303031029183019190915260019190821682146121165760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b508115801561212d575033600160a060020a038516145b156121a757604080518082019091526006815260d160020a6518189b98181902602082015260018416156121a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505b600160a060020a0384166000818152600b602052604080822080548719169055518592917fbb71944f65b9a48cc7d835179fb5e874f29b60aa0195785fb54968d8dddef08a91a350505050565b600c5460a060020a900460ff161561220b57600080fd5b6000818152601260205260409020548190600160a060020a0316331461223057600080fd5b600082815260126020526040902060020154421061224d57600080fd5b60008281526012602081815260408084208054600984528286208054600160a060020a031916600160a060020a0392831617905560088452919094205492909152915461229f92918216911684613255565b6040805183815290516000805160206140258339815191529181900360200190a15050565b83336122d08282611b0d565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d02815250906123415760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561235957600080fd5b6000831161236657600080fd5b83156123a3576000868152600e6020908152604080832086845290915290208054600160a060020a031916600160a060020a0387161790556123cb565b6000868152600e6020908152604080832086845290915290208054600160a060020a03191690555b60408051878152600160a060020a0387166020820152851515818301526060810185905290517fd4fada85986a6a990ebf8397071db3525f738377b4b8d4c3e9c8847dd7c7bd409181900360800190a1505050505050565b61246585858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061353592505050565b5050505050565b600080821160405180604001604052806006815260200160d060020a6530313730303302815250906124e25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5050600160a060020a03919091166000908152600b602052604090205481161490565b60009081526011602052604090205490565b6000818152600860209081526040918290205482518084019093526006835260d060020a65303037303033029183019190915260609190600160a060020a03166125a55760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000828152600d6020526040902054600260001961010060018416150201909116041561266c576000828152600d602090815260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845290918301828280156126605780601f1061263557610100808354040283529160200191612660565b820191906000526020600020905b81548152906001019060200180831161264357829003601f168201915b50505050509050610c3a565b60036126778361396e565b60405160200180838054600181600116156101000203166002900480156126d55780601f106126b35761010080835404028352918201916126d5565b820191906000526020600020905b8154815290600101906020018083116126c1575b5050825160208401908083835b602083106127015780518252601f1990920191602091820191016126e2565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529050610c3a565b60008281526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166127c75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50506000918252600e60209081526040808420928452919052902054600160a060020a031690565b60008181526008602090815260408083205481518083019092526006825260d160020a6518181b181819029282019290925290600160a060020a03166128795760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505060009081526012602052604090206002015490565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a6530313730303102928401929092529091600291821682146129355760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff161561294d57600080fd5b6129908888600187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3f92505050565b61299957600080fd5b6040805160208082018b9052600160a060020a0388168284015282518083038401815260609092019092528051910120876129d382613a38565b146129dd57600080fd5b60008981526009602052604090208054600160a060020a0319163317905586612a29576000898152600e602090815260408083206001845290915290208054600160a060020a03191690555b600089815260086020526040902054612a4c90600160a060020a0316878b613255565b50505060009586525050601160205250506040822080549290555090565b600160a060020a039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b604080518082018252600680825260d060020a6530313730303302602092830152336000908152600b835283812054845180860190955291845260d060020a653031373030310292840192909252909160029182168214612b3d5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c5460a060020a900460ff1615612b5557600080fd5b8883612b618282611b0d565b60405180604001604052806006815260200160d260020a650c0c0dcc0c0d0281525090612bd25760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008b8152601260209081526040918290206001015482518084019093526006835260d160020a6518181b98181b029183019190915215612c585760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008b8152600e6020908152604080832083805282528083208054600160a060020a031916600160a060020a038d161790558d8352600f82528083208d9055600d82529091208a514292612cb19291908d0190613f12565b506013546040805160e060020a6387159d9b028152600481018f9052600160a060020a038981166024830152915191909216916387159d9b91604480830192600092919082900301818387803b158015612d0a57600080fd5b505af1158015612d1e573d6000803e3d6000fd5b505050508615612d5c5760008c8152600e602090815260408083206001845290915290208054600160a060020a031916600160a060020a038b161790555b612d64613f80565b604051806060016040528088600160a060020a031681526020018381526020018a815250905080601260008f815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010155604082015181600201559050507f0166db8152debe7d1cfed1b1e12a32a28a986839ab44dff49682be23e29704de8d8d8d8d8d8d88604051808881526020018781526020018060200186600160a060020a0316600160a060020a0316815260200185815260200184151515158152602001838152602001828103825287818151815260200191508051906020019080838360005b83811015612e81578181015183820152602001612e69565b50505050905090810190601f168015612eae5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390a15050506000998a5250506011602052505060409095205495945050505050565b600c54604080518082019091526006815260d060020a6530313830303102602082015290600160a060020a03163314612f5e5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50604080518082019091526006815260d160020a6518189c181819026020820152600160a060020a038216612fd75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600c54604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600c8054600160a060020a031916600160a060020a0392909216919091179055565b600c5460a060020a900460ff161561304b57600080fd5b6000828152601260205260409020548290600160a060020a0316331461307057600080fd5b600083815260106020908152604091829020805460ff19168515159081179091558251868152918201528151600080516020614005833981519152929181900390910190a1505050565b6000908152600e6020908152604080832060018452909152902054600160a060020a0316151590565b6003805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156131695780601f1061313e57610100808354040283529160200191613169565b820191906000526020600020905b81548152906001019060200180831161314c57829003601f168201915b505050505081565b6000815160411461318457506000611575565b60208201516040830151606084015160001a6fa2a8918ca85bafe22016d0b997e4df6060ff60020a038211156131c05760009350505050611575565b8060ff16601b141580156131d857508060ff16601c14155b156131e95760009350505050611575565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa158015613240573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6014546040805160e160020a6372331c73028152600160a060020a0386811660048301528581166024830152604482018590529151919092169163e46638e69160648083019260209291908290030181600087803b1580156132b657600080fd5b505af11580156132ca573d6000803e3d6000fd5b505050506040513d60208110156132e057600080fd5b50516132eb57600080fd5b6132f6838383613a89565b6013546040805160e060020a6387159d9b02815260048101849052600160a060020a038681166024830152915191909216916387159d9b91604480830192600092919082900301818387803b15801561334e57600080fd5b505af1158015613362573d6000803e3d6000fd5b50505050505050565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a0383166133e35760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b18181b0291830191909152600160a060020a03161561346f5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b5060008181526008602090815260408083208054600160a060020a031916600160a060020a038716908117909155808452600683528184208054600181810183559186528486208101879055868652600785528386205560048054918201908190557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b8201879055600590945282852055905191928492600080516020614045833981519152908290a4505050565b8051613531906003906020840190613f12565b5050565b61354783600160a060020a0316613e8e565b156136c35760405160e160020a630a85bd01028082523360048301818152600160a060020a0388811660248601526044850187905260806064860190815286516084870152865194959189169463150b7a0294938b938a938a93909160a40190602085019080838360005b838110156135ca5781810151838201526020016135b2565b50505050905090810190601f1680156135f75780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561361957600080fd5b505af115801561362d573d6000803e3d6000fd5b505050506040513d602081101561364357600080fd5b5051604080518082019091526006815260d060020a6530303630303502602082015291600160e060020a0319909116146136c15760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b505b6136ce848484613255565b50505050565b6000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a031690816137605760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600082815260096020526040902054600160a060020a03161561379b5760008281526009602052604090208054600160a060020a03191690555b600160a060020a0381166000908152600660205260409020546137ba57fe5b600082815260076020908152604080832054600160a060020a0385168452600690925282205490916000199091019081831461387357600160a060020a038416600090815260066020526040902080548390811061381457fe5b90600052602060002001549050806006600086600160a060020a0316600160a060020a03168152602001908152602001600020848154811061385257fe5b60009182526020808320909101929092558281526007909152604090208390555b60008581526008602090815260408083208054600160a060020a031916905560078252808320839055600160a060020a0387168352600690915290208054906138c0906000198301613faa565b506004546138ca57fe5b6000858152600560205260409020546004805460001981019450849081106138ee57fe5b90600052602060002001549150816004828154811061390957fe5b6000918252602090912001556004805490613928906000198301613faa565b5060008281526005602052604080822083905587825280822082905551879190600160a060020a03881690600080516020614045833981519152908390a4505050505050565b6060816139965750604080518082019091526001815260fc60020a6003026020820152610c3a565b8160005b81156139ae57600101600a8204915061399a565b6060816040519080825280601f01601f1916602001820160405280156139db576020820181803883390190505b50859350905060001982015b8315613a2f57600a840660300160f860020a0282828060019003935081518110613a0d57fe5b6020010190600160f860020a031916908160001a905350600a840493506139e7565b50949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038416613b015760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b506000818152600860209081526040918290205482518084019093526006835260d160020a6518181b1818190291830191909152600160a060020a03858116911614613b915760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50604080518082019091526006815260d060020a65303036303031026020820152600160a060020a038316613c0a5760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600160a060020a038316331480613c385750600081815260096020526040902054600160a060020a031633145b80613c665750600160a060020a0383166000908152600a6020908152604080832033845290915290205460ff165b60405180604001604052806006815260200160d260020a650c0c0d8c0c0d0281525090613cd75760405160e560020a62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610da0578181015183820152602001610d88565b50600081815260096020526040902054600160a060020a031615613d125760008181526009602052604090208054600160a060020a03191690555b600160a060020a038316600090815260066020526040902054613d3157fe5b600081815260076020908152604080832054600160a060020a038716845260069092529091205460001901808214613de557600160a060020a0385166000908152600660205260408120805483908110613d8757fe5b90600052602060002001549050806006600088600160a060020a0316600160a060020a031681526020019081526020016000208481548110613dc557fe5b600091825260208083209091019290925591825260079052604090208290555b600160a060020a0385166000908152600660205260409020805490613e0e906000198301613faa565b5060008381526008602090815260408083208054600160a060020a031916600160a060020a038981169182179092558085526006845282852080546001810180835591875285872081018a9055898752600790955283862094909455915192938793918a16916000805160206140458339815191529190a4505050505050565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613ed55782800160ff19823516178555613f02565b82800160010185558215613f02579182015b82811115613f02578235825591602001919060010190613ee7565b50613f0e929150613fca565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613f5357805160ff1916838001178555613f02565b82800160010185558215613f02579182015b82811115613f02578251825591602001919060010190613f65565b60405180606001604052806000600160a060020a0316815260200160008152602001600081525090565b8154818355818111156112b1576000838152602090206112b19181019083015b61115491905b80821115613f0e5760008155600101613fd056feb5fa77bd6bc3d862c73fa2474bfb96a0f76d38b622c54ff2a0188be82fb9651106eb2a6b59bafdf7d5d15a5fe2681abd76406ddf85d0af873cd23c221014dc3211cd3c497c4ee51feb1ed7bbb2d072b8c18bce7bbf0cf03d310a12b4afcd9818ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820e9896e5a1e3faba7c7f12686854a548c7a25f66710bc5a5f38be182b40660cd80029