Contract 0xb5da84cdc928765c15a8192bf3c6649e7802772b

 

Contract Overview

Balance:
0.065 Ether

EtherValue:
$112.85 (@ $1,736.15/ETH)

Token:
Txn Hash
Block
From
To
Value
0x6de07db5f990baccbd9fbed972a0e7151bc7675f9e249108fdcc323e57e58f6d65759722018-10-24 17:16:49866 days 47 mins ago0x9727ece88acf7ab2014715465d5353e49f6a693a IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.065 Ether0.0018511227988.8359927
0xbf6930da5e32752fa20c0bd5d18360bc0e8535d8fc1e11623cc967011d90f15465713562018-10-23 23:12:41866 days 18 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.00007811252.50000001
0xbc8a4e937a6973be4973a4512495f9a4e9552b1310bf4350194c6ca4e2b13c6565569552018-10-21 14:53:21869 days 3 hrs ago0x9ea5153c606f1301576920108b87c4de8503ab9c IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.325 Ether0.001122495
0x88cefcb7c2b2697338dbcdb4537458cb2a08c496a641b057d418a0d2429b7f6356414202018-05-19 16:28:351024 days 1 hr ago0x648abda15186b1e4587722009497c8e3c9242c6b IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.195 Ether0.0018854829
0xf054c974c090b377b1838d10f9baf77be22223ed59b31ef72a86fae5215d79da55167282018-04-27 20:25:431045 days 21 hrs ago0x07efcbf06a74f2e8f2dae7dc989b1d0f3d694b0b IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.165 Ether0.0006284943
0xaf80ff95547cfd8d89774d6baafca3d943c4f7c602d2387da802245a87e3046454689052018-04-19 14:41:331054 days 3 hrs ago0x07efcbf06a74f2e8f2dae7dc989b1d0f3d694b0b IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.065 Ether0.0004189962
0xd1eab8b98df856a25c4f20cbb5b56fd688f791696ba46c97645299d8a1e44f1a54587592018-04-17 20:40:481055 days 21 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0001920200011.00000001
0xac24e5d7e95047d2a4be19dd04517d614bb25c670124c47e06ef5fdf260e772354521392018-04-16 17:40:261057 days 23 mins ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0001920200011.00000001
0x7e855857d2a59bbeaf3c13ed55d9d940d7684ab8441f5b8754e39cb369f96e6454521172018-04-16 17:33:321057 days 30 mins ago0x648abda15186b1e4587722009497c8e3c9242c6b IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.065 Ether0.0002094981
0x9f4efb3e121e6760f6b61657a77aa9184cd3c0bdef9aef4b9e94e04e264d948b54416182018-04-14 22:55:021058 days 19 hrs ago0x675b63414c972923cfc33e0d08d18460df01a80f IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.065 Ether0.0002094981
0x2bd9cb1810a8b7de39385c1300397921ac3fe8cad4c1c0385a7f452568fe1d0454299042018-04-12 23:26:551060 days 18 hrs ago0xc41215fa143b62c5ae8f517e2a6afdd1252e1916 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.165 Ether0.0002094981
0x2e15228011975b9db9e4861e8f56cb20a3713906f7d58c1aa5d59691ccaab9a954295332018-04-12 21:44:041060 days 20 hrs ago0x534c58c33e2e6c651ebebaa2b1a5be95efb599e7 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.165 Ether0.0008977364
0x42c52e6d30b78326cf2954815205b5a414b263d741c8829e2d5c916655a2543b54287972018-04-12 18:45:511060 days 23 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.000031981.00000001
0xfd17a1289d06c635dc75f42e7a1f19557f7f8aa9233f435b01fcfe5645f1932e54287682018-04-12 18:40:101060 days 23 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312451.00000001
0x99284d5c763c5223e4538f87191a3d849eb457c551bf6d9fc53e3db0e461d41954287462018-04-12 18:34:171060 days 23 hrs ago0xf1b867bbc9a36320866d51cd020cd356d2cfb767 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0.065 Ether0.0004489962
0xe77ac62ea9c240002992e37168833764c01d6a3524e7e4212da0013ffba41baa54230212018-04-11 19:29:111061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
0xef7cadb9b784ee53da5b26154502d2f75d9157bd700a67a543cf6710f65520b154230212018-04-11 19:29:111061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
0xc9235f8153d51834962bbdaf234c601534725a2916c910736dcc616efccba5fd54230182018-04-11 19:28:201061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
0x0369ad569f119a106cc2a25cebd3dd7a0b34ab36f8e8914b71a813ee857cc79f54230112018-04-11 19:26:161061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
0x700d1b2488d162cb2f476f257a0b944f1a9e6b4f04fdb24a082ba1c8191cfada54230102018-04-11 19:26:121061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
0x409090c09c686d6a7c87849eda5aa29a809c5b5d23abff106d4c3db04bd2814b54230022018-04-11 19:24:471061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
0x65ee95c55b572a9c9446e1ddf45ff741bd0d108db545b9b3f665cea2f62be86d54229952018-04-11 19:22:321061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
0xe075b0f2508ffb7ad4b69c87fa7974f3ef57f2a212456d214356cd536d4d9c2754229512018-04-11 19:11:181061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
0x320d50805f1503c2d426359e6816ca964ab3ef3d0b9bc3dd0921bfd222043aab54229412018-04-11 19:09:211061 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000447171.00000001
0xbdad5a8f9e8ca97169b551e1bdbe1649681354d742188d0842817ff074ddcb0653927612018-04-06 19:06:331066 days 22 hrs ago0x62799b3b97baac306498f721079f3a9405a91e41 IN  0xb5da84cdc928765c15a8192bf3c6649e7802772b0 Ether0.0000312071.00000001
[ Download CSV Export 
Latest 2 internal transactions
Parent Txn Hash Block From To Value
0xbf6930da5e32752fa20c0bd5d18360bc0e8535d8fc1e11623cc967011d90f15465713562018-10-23 23:12:41866 days 18 hrs ago 0xb5da84cdc928765c15a8192bf3c6649e7802772b0x62799b3b97baac306498f721079f3a9405a91e411.21 Ether
0xfd17a1289d06c635dc75f42e7a1f19557f7f8aa9233f435b01fcfe5645f1932e54287682018-04-12 18:40:101060 days 23 hrs ago 0xb5da84cdc928765c15a8192bf3c6649e7802772b0x62799b3b97baac306498f721079f3a9405a91e410.065 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LicenseCore

Compiler Version
v0.4.19+commit.c4cbbb05

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2018-04-02
*/

pragma solidity ^0.4.13;

interface ERC721Enumerable /* is ERC721 */ {
    /// @notice Count NFTs tracked by this contract
    /// @return 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
    function totalSupply() public view returns (uint256);

    /// @notice Enumerate valid NFTs
    /// @dev Throws if `_index` >= `totalSupply()`.
    /// @param _index A counter less than `totalSupply()`
    /// @return The token identifier for the `_index`th NFT,
    ///  (sort order not specified)
    function tokenByIndex(uint256 _index) external view returns (uint256);

    /// @notice Enumerate NFTs assigned to an owner
    /// @dev 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 The token identifier for the `_index`th NFT assigned to `_owner`,
    ///   (sort order not specified)
    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 _tokenId);
}

interface ERC721Metadata /* is ERC721 */ {
    /// @notice A descriptive name for a collection of NFTs in this contract
    function name() external pure returns (string _name);

    /// @notice An abbreviated name for NFTs in this contract
    function symbol() external pure returns (string _symbol);

    /// @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".
    function tokenURI(uint256 _tokenId) external view returns (string);
}

contract Ownable {
  address public owner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

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

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == 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));
    OwnershipTransferred(owner, _newOwner);
    owner = _newOwner;
  }

}

interface ERC721TokenReceiver {
    /// @notice Handle the receipt of an NFT
    /// @dev The ERC721 smart contract calls this function on the recipient
    ///  after a `transfer`. This function MAY throw to revert and reject the
    ///  transfer. This function MUST use 50,000 gas or less. Return of other
    ///  than the magic value MUST result in the transaction being reverted.
    ///  Note: the contract address is always the message sender.
    /// @param _from The sending address
    /// @param _tokenId The NFT identifier which is being transfered
    /// @param _data Additional data with no specified format
    /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
    ///  unless throwing
	function onERC721Received(address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
}

library Math {
  function max64(uint64 a, uint64 b) internal pure returns (uint64) {
    return a >= b ? a : b;
  }

  function min64(uint64 a, uint64 b) internal pure returns (uint64) {
    return a < b ? a : b;
  }

  function max256(uint256 a, uint256 b) internal pure returns (uint256) {
    return a >= b ? a : b;
  }

  function min256(uint256 a, uint256 b) internal pure returns (uint256) {
    return a < b ? a : b;
  }
}

contract LicenseAccessControl {
  /**
   * @notice ContractUpgrade is the event that will be emitted if we set a new contract address
   */
  event ContractUpgrade(address newContract);
  event Paused();
  event Unpaused();

  /**
   * @notice CEO's address FOOBAR
   */
  address public ceoAddress;

  /**
   * @notice CFO's address
   */
  address public cfoAddress;

  /**
   * @notice COO's address
   */
  address public cooAddress;

  /**
   * @notice withdrawal address
   */
  address public withdrawalAddress;

  bool public paused = false;

  /**
   * @dev Modifier to make a function only callable by the CEO
   */
  modifier onlyCEO() {
    require(msg.sender == ceoAddress);
    _;
  }

  /**
   * @dev Modifier to make a function only callable by the CFO
   */
  modifier onlyCFO() {
    require(msg.sender == cfoAddress);
    _;
  }

  /**
   * @dev Modifier to make a function only callable by the COO
   */
  modifier onlyCOO() {
    require(msg.sender == cooAddress);
    _;
  }

  /**
   * @dev Modifier to make a function only callable by C-level execs
   */
  modifier onlyCLevel() {
    require(
      msg.sender == cooAddress ||
      msg.sender == ceoAddress ||
      msg.sender == cfoAddress
    );
    _;
  }

  /**
   * @dev Modifier to make a function only callable by CEO or CFO
   */
  modifier onlyCEOOrCFO() {
    require(
      msg.sender == cfoAddress ||
      msg.sender == ceoAddress
    );
    _;
  }

  /**
   * @dev Modifier to make a function only callable by CEO or COO
   */
  modifier onlyCEOOrCOO() {
    require(
      msg.sender == cooAddress ||
      msg.sender == ceoAddress
    );
    _;
  }

  /**
   * @notice Sets a new CEO
   * @param _newCEO - the address of the new CEO
   */
  function setCEO(address _newCEO) external onlyCEO {
    require(_newCEO != address(0));
    ceoAddress = _newCEO;
  }

  /**
   * @notice Sets a new CFO
   * @param _newCFO - the address of the new CFO
   */
  function setCFO(address _newCFO) external onlyCEO {
    require(_newCFO != address(0));
    cfoAddress = _newCFO;
  }

  /**
   * @notice Sets a new COO
   * @param _newCOO - the address of the new COO
   */
  function setCOO(address _newCOO) external onlyCEO {
    require(_newCOO != address(0));
    cooAddress = _newCOO;
  }

  /**
   * @notice Sets a new withdrawalAddress
   * @param _newWithdrawalAddress - the address where we'll send the funds
   */
  function setWithdrawalAddress(address _newWithdrawalAddress) external onlyCEO {
    require(_newWithdrawalAddress != address(0));
    withdrawalAddress = _newWithdrawalAddress;
  }

  /**
   * @notice Withdraw the balance to the withdrawalAddress
   * @dev We set a withdrawal address seperate from the CFO because this allows us to withdraw to a cold wallet.
   */
  function withdrawBalance() external onlyCEOOrCFO {
    require(withdrawalAddress != address(0));
    withdrawalAddress.transfer(this.balance);
  }

  /** Pausable functionality adapted from OpenZeppelin **/

  /**
   * @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);
    _;
  }

  /**
   * @notice called by any C-level to pause, triggers stopped state
   */
  function pause() public onlyCLevel whenNotPaused {
    paused = true;
    Paused();
  }

  /**
   * @notice called by the CEO to unpause, returns to normal state
   */
  function unpause() public onlyCEO whenPaused {
    paused = false;
    Unpaused();
  }
}

contract LicenseBase is LicenseAccessControl {
  /**
   * @notice Issued is emitted when a new license is issued
   */
  event LicenseIssued(
    address indexed owner,
    address indexed purchaser,
    uint256 licenseId,
    uint256 productId,
    uint256 attributes,
    uint256 issuedTime,
    uint256 expirationTime,
    address affiliate
  );

  event LicenseRenewal(
    address indexed owner,
    address indexed purchaser,
    uint256 licenseId,
    uint256 productId,
    uint256 expirationTime
  );

  struct License {
    uint256 productId;
    uint256 attributes;
    uint256 issuedTime;
    uint256 expirationTime;
    address affiliate;
  }

  /**
   * @notice All licenses in existence.
   * @dev The ID of each license is an index in this array.
   */
  License[] licenses;

  /** internal **/
  function _isValidLicense(uint256 _licenseId) internal view returns (bool) {
    return licenseProductId(_licenseId) != 0;
  }

  /** anyone **/

  /**
   * @notice Get a license's productId
   * @param _licenseId the license id
   */
  function licenseProductId(uint256 _licenseId) public view returns (uint256) {
    return licenses[_licenseId].productId;
  }

  /**
   * @notice Get a license's attributes
   * @param _licenseId the license id
   */
  function licenseAttributes(uint256 _licenseId) public view returns (uint256) {
    return licenses[_licenseId].attributes;
  }

  /**
   * @notice Get a license's issueTime
   * @param _licenseId the license id
   */
  function licenseIssuedTime(uint256 _licenseId) public view returns (uint256) {
    return licenses[_licenseId].issuedTime;
  }

  /**
   * @notice Get a license's issueTime
   * @param _licenseId the license id
   */
  function licenseExpirationTime(uint256 _licenseId) public view returns (uint256) {
    return licenses[_licenseId].expirationTime;
  }

  /**
   * @notice Get a the affiliate credited for the sale of this license
   * @param _licenseId the license id
   */
  function licenseAffiliate(uint256 _licenseId) public view returns (address) {
    return licenses[_licenseId].affiliate;
  }

  /**
   * @notice Get a license's info
   * @param _licenseId the license id
   */
  function licenseInfo(uint256 _licenseId)
    public view returns (uint256, uint256, uint256, uint256, address)
  {
    return (
      licenseProductId(_licenseId),
      licenseAttributes(_licenseId),
      licenseIssuedTime(_licenseId),
      licenseExpirationTime(_licenseId),
      licenseAffiliate(_licenseId)
    );
  }
}

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;
    Pause();
  }

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

contract AffiliateProgram is Pausable {
  using SafeMath for uint256;

  event AffiliateCredit(
    // The address of the affiliate
    address affiliate,
    // The store's ID of what was sold (e.g. a tokenId)
    uint256 productId,
    // The amount owed this affiliate in this sale
    uint256 amount
  );

  event Withdraw(address affiliate, address to, uint256 amount);
  event Whitelisted(address affiliate, uint256 amount);
  event RateChanged(uint256 rate, uint256 amount);

  // @notice A mapping from affiliate address to their balance
  mapping (address => uint256) public balances;

  // @notice A mapping from affiliate address to the time of last deposit
  mapping (address => uint256) public lastDepositTimes;

  // @notice The last deposit globally
  uint256 public lastDepositTime;

  // @notice The maximum rate for any affiliate
  // @dev The hard-coded maximum affiliate rate (in basis points)
  // All rates are measured in basis points (1/100 of a percent)
  // Values 0-10,000 map to 0%-100%
  uint256 private constant hardCodedMaximumRate = 5000;

  // @notice The commission exiration time
  // @dev Affiliate commissions expire if they are unclaimed after this amount of time
  uint256 private constant commissionExpiryTime = 30 days;

  // @notice The baseline affiliate rate (in basis points) for non-whitelisted referrals
  uint256 public baselineRate = 0;

  // @notice A mapping from whitelisted referrals to their individual rates
  mapping (address => uint256) public whitelistRates;

  // @notice The maximum rate for any affiliate
  // @dev overrides individual rates. This can be used to clip the rate used in bulk, if necessary
  uint256 public maximumRate = 5000;

  // @notice The address of the store selling products
  address public storeAddress;

  // @notice The contract is retired
  // @dev If we decide to retire this program, this value will be set to true
  // and then the contract cannot be unpaused
  bool public retired = false;


  /**
   * @dev Modifier to make a function only callable by the store or the owner
   */
  modifier onlyStoreOrOwner() {
    require(
      msg.sender == storeAddress ||
      msg.sender == owner);
    _;
  }

  /**
   * @dev AffiliateProgram constructor - keeps the address of it's parent store
   * and pauses the contract
   */
  function AffiliateProgram(address _storeAddress) public {
    require(_storeAddress != address(0));
    storeAddress = _storeAddress;
    paused = true;
  }

  /**
   * @notice Exposes that this contract thinks it is an AffiliateProgram
   */
  function isAffiliateProgram() public pure returns (bool) {
    return true;
  }

  /**
   * @notice returns the commission rate for a sale
   *
   * @dev rateFor returns the rate which should be used to calculate the comission
   *  for this affiliate/sale combination, in basis points (1/100th of a percent).
   *
   *  We may want to completely blacklist a particular address (e.g. a known bad actor affilite).
   *  To that end, if the whitelistRate is exactly 1bp, we use that as a signal for blacklisting
   *  and return a rate of zero. The upside is that we can completely turn off
   *  sending transactions to a particular address when this is needed. The
   *  downside is that you can't issued 1/100th of a percent commission.
   *  However, since this is such a small amount its an acceptable tradeoff.
   *
   *  This implementation does not use the _productId, _pruchaseId,
   *  _purchaseAmount, but we include them here as part of the protocol, because
   *  they could be useful in more advanced affiliate programs.
   *
   * @param _affiliate - the address of the affiliate to check for
   */
  function rateFor(
    address _affiliate,
    uint256 /*_productId*/,
    uint256 /*_purchaseId*/,
    uint256 /*_purchaseAmount*/)
    public
    view
    returns (uint256)
  {
    uint256 whitelistedRate = whitelistRates[_affiliate];
    if(whitelistedRate > 0) {
      // use 1 bp as a blacklist signal
      if(whitelistedRate == 1) {
        return 0;
      } else {
        return Math.min256(whitelistedRate, maximumRate);
      }
    } else {
      return Math.min256(baselineRate, maximumRate);
    }
  }

  /**
   * @notice cutFor returns the affiliate cut for a sale
   * @dev cutFor returns the cut (amount in wei) to give in comission to the affiliate
   *
   * @param _affiliate - the address of the affiliate to check for
   * @param _productId - the productId in the sale
   * @param _purchaseId - the purchaseId in the sale
   * @param _purchaseAmount - the purchaseAmount
   */
  function cutFor(
    address _affiliate,
    uint256 _productId,
    uint256 _purchaseId,
    uint256 _purchaseAmount)
    public
    view
    returns (uint256)
  {
    uint256 rate = rateFor(
      _affiliate,
      _productId,
      _purchaseId,
      _purchaseAmount);
    require(rate <= hardCodedMaximumRate);
    return (_purchaseAmount.mul(rate)).div(10000);
  }

  /**
   * @notice credit an affiliate for a purchase
   * @dev credit accepts eth and credits the affiliate's balance for the amount
   *
   * @param _affiliate - the address of the affiliate to credit
   * @param _purchaseId - the purchaseId of the sale
   */
  function credit(
    address _affiliate,
    uint256 _purchaseId)
    public
    onlyStoreOrOwner
    whenNotPaused
    payable
  {
    require(msg.value > 0);
    require(_affiliate != address(0));
    balances[_affiliate] += msg.value;
    lastDepositTimes[_affiliate] = now; // solium-disable-line security/no-block-members
    lastDepositTime = now; // solium-disable-line security/no-block-members
    AffiliateCredit(_affiliate, _purchaseId, msg.value);
  }

  /**
   * @dev _performWithdraw performs a withdrawal from address _from and
   * transfers it to _to. This can be different because we allow the owner
   * to withdraw unclaimed funds after a period of time.
   *
   * @param _from - the address to subtract balance from
   * @param _to - the address to transfer ETH to
   */
  function _performWithdraw(address _from, address _to) private {
    require(balances[_from] > 0);
    uint256 balanceValue = balances[_from];
    balances[_from] = 0;
    _to.transfer(balanceValue);
    Withdraw(_from, _to, balanceValue);
  }

  /**
   * @notice withdraw
   * @dev withdraw the msg.sender's balance
   */
  function withdraw() public whenNotPaused {
    _performWithdraw(msg.sender, msg.sender);
  }

  /**
   * @notice withdraw from a specific account
   * @dev withdrawFrom allows the owner to withdraw an affiliate's unclaimed
   * ETH, after the alotted time.
   *
   * This function can be called even if the contract is paused
   *
   * @param _affiliate - the address of the affiliate
   * @param _to - the address to send ETH to
   */
  function withdrawFrom(address _affiliate, address _to) onlyOwner public {
    // solium-disable-next-line security/no-block-members
    require(now > lastDepositTimes[_affiliate].add(commissionExpiryTime));
    _performWithdraw(_affiliate, _to);
  }

  /**
   * @notice retire the contract (dangerous)
   * @dev retire - withdraws the entire balance and marks the contract as retired, which
   * prevents unpausing.
   *
   * If no new comissions have been deposited for the alotted time,
   * then the owner may pause the program and retire this contract.
   * This may only be performed once as the contract cannot be unpaused.
   *
   * We do this as an alternative to selfdestruct, because certain operations
   * can still be performed after the contract has been selfdestructed, such as
   * the owner withdrawing ETH accidentally sent here.
   */
  function retire(address _to) onlyOwner whenPaused public {
    // solium-disable-next-line security/no-block-members
    require(now > lastDepositTime.add(commissionExpiryTime));
    _to.transfer(this.balance);
    retired = true;
  }

  /**
   * @notice whitelist an affiliate address
   * @dev whitelist - white listed affiliates can receive a different
   *   rate than the general public (whitelisted accounts would generally get a
   *   better rate).
   * @param _affiliate - the affiliate address to whitelist
   * @param _rate - the rate, in basis-points (1/100th of a percent) to give this affiliate in each sale. NOTE: a rate of exactly 1 is the signal to blacklist this affiliate. That is, a rate of 1 will set the commission to 0.
   */
  function whitelist(address _affiliate, uint256 _rate) onlyOwner public {
    require(_rate <= hardCodedMaximumRate);
    whitelistRates[_affiliate] = _rate;
    Whitelisted(_affiliate, _rate);
  }

  /**
   * @notice set the rate for non-whitelisted affiliates
   * @dev setBaselineRate - sets the baseline rate for any affiliate that is not whitelisted
   * @param _newRate - the rate, in bp (1/100th of a percent) to give any non-whitelisted affiliate. Set to zero to "turn off"
   */
  function setBaselineRate(uint256 _newRate) onlyOwner public {
    require(_newRate <= hardCodedMaximumRate);
    baselineRate = _newRate;
    RateChanged(0, _newRate);
  }

  /**
   * @notice set the maximum rate for any affiliate
   * @dev setMaximumRate - Set the maximum rate for any affiliate, including whitelists. That is, this overrides individual rates.
   * @param _newRate - the rate, in bp (1/100th of a percent)
   */
  function setMaximumRate(uint256 _newRate) onlyOwner public {
    require(_newRate <= hardCodedMaximumRate);
    maximumRate = _newRate;
    RateChanged(1, _newRate);
  }

  /**
   * @notice unpause the contract
   * @dev called by the owner to unpause, returns to normal state. Will not
   * unpause if the contract is retired.
   */
  function unpause() onlyOwner whenPaused public {
    require(!retired);
    paused = false;
    Unpause();
  }

}

contract ERC721 {
  event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
  event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
  event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

  function balanceOf(address _owner) public view returns (uint256 _balance);
  function ownerOf(uint256 _tokenId) public view returns (address _owner);
  function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) public;
  function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
  function transfer(address _to, uint256 _tokenId) external;
  function transferFrom(address _from, address _to, uint256 _tokenId) public;
  function approve(address _to, uint256 _tokenId) external;
  function setApprovalForAll(address _to, bool _approved) external;
  function getApproved(uint256 _tokenId) public view returns (address);
  function isApprovedForAll(address _owner, address _operator) public view returns (bool);
}

contract LicenseInventory is LicenseBase {
  using SafeMath for uint256;

  event ProductCreated(
    uint256 id,
    uint256 price,
    uint256 available,
    uint256 supply,
    uint256 interval,
    bool renewable
  );
  event ProductInventoryAdjusted(uint256 productId, uint256 available);
  event ProductPriceChanged(uint256 productId, uint256 price);
  event ProductRenewableChanged(uint256 productId, bool renewable);


  /**
   * @notice Product defines a product
   * * renewable: There may come a time when we which to disable the ability to renew a subscription. For example, a plan we no longer wish to support. Obviously care needs to be taken with how we communicate this to customers, but contract-wise, we want to support the ability to discontinue renewal of certain plans.
  */
  struct Product {
    uint256 id;
    uint256 price;
    uint256 available;
    uint256 supply;
    uint256 sold;
    uint256 interval;
    bool renewable;
  }

  // @notice All products in existence
  uint256[] public allProductIds;

  // @notice A mapping from product ids to Products
  mapping (uint256 => Product) public products;

  /*** internal ***/

  /**
   * @notice _productExists checks to see if a product exists
   */
  function _productExists(uint256 _productId) internal view returns (bool) {
    return products[_productId].id != 0;
  }

  function _productDoesNotExist(uint256 _productId) internal view returns (bool) {
    return products[_productId].id == 0;
  }

  function _createProduct(
    uint256 _productId,
    uint256 _initialPrice,
    uint256 _initialInventoryQuantity,
    uint256 _supply,
    uint256 _interval)
    internal
  {
    require(_productDoesNotExist(_productId));
    require(_initialInventoryQuantity <= _supply);

    Product memory _product = Product({
      id: _productId,
      price: _initialPrice,
      available: _initialInventoryQuantity,
      supply: _supply,
      sold: 0,
      interval: _interval,
      renewable: _interval == 0 ? false : true
    });

    products[_productId] = _product;
    allProductIds.push(_productId);

    ProductCreated(
      _product.id,
      _product.price,
      _product.available,
      _product.supply,
      _product.interval,
      _product.renewable
      );
  }

  function _incrementInventory(
    uint256 _productId,
    uint256 _inventoryAdjustment)
    internal
  {
    require(_productExists(_productId));
    uint256 newInventoryLevel = products[_productId].available.add(_inventoryAdjustment);

    // A supply of "0" means "unlimited". Otherwise we need to ensure that we're not over-creating this product
    if(products[_productId].supply > 0) {
      // you have to take already sold into account
      require(products[_productId].sold.add(newInventoryLevel) <= products[_productId].supply);
    }

    products[_productId].available = newInventoryLevel;
  }

  function _decrementInventory(
    uint256 _productId,
    uint256 _inventoryAdjustment)
    internal
  {
    require(_productExists(_productId));
    uint256 newInventoryLevel = products[_productId].available.sub(_inventoryAdjustment);
    // unnecessary because we're using SafeMath and an unsigned int
    // require(newInventoryLevel >= 0);
    products[_productId].available = newInventoryLevel;
  }

  function _clearInventory(uint256 _productId) internal
  {
    require(_productExists(_productId));
    products[_productId].available = 0;
  }

  function _setPrice(uint256 _productId, uint256 _price) internal
  {
    require(_productExists(_productId));
    products[_productId].price = _price;
  }

  function _setRenewable(uint256 _productId, bool _isRenewable) internal
  {
    require(_productExists(_productId));
    products[_productId].renewable = _isRenewable;
  }

  function _purchaseOneUnitInStock(uint256 _productId) internal {
    require(_productExists(_productId));
    require(availableInventoryOf(_productId) > 0);

    // lower inventory
    _decrementInventory(_productId, 1);

    // record that one was sold
    products[_productId].sold = products[_productId].sold.add(1);
  }

  function _requireRenewableProduct(uint256 _productId) internal view {
    // productId must exist
    require(_productId != 0);
    // You can only renew a subscription product
    require(isSubscriptionProduct(_productId));
    // The product must currently be renewable
    require(renewableOf(_productId));
  }

  /*** public ***/

  /** executives-only **/

  /**
   * @notice createProduct creates a new product in the system
   * @param _productId - the id of the product to use (cannot be changed)
   * @param _initialPrice - the starting price (price can be changed)
   * @param _initialInventoryQuantity - the initial inventory (inventory can be changed)
   * @param _supply - the total supply - use `0` for "unlimited" (cannot be changed)
   */
  function createProduct(
    uint256 _productId,
    uint256 _initialPrice,
    uint256 _initialInventoryQuantity,
    uint256 _supply,
    uint256 _interval)
    external
    onlyCEOOrCOO
  {
    _createProduct(
      _productId,
      _initialPrice,
      _initialInventoryQuantity,
      _supply,
      _interval);
  }

  /**
   * @notice incrementInventory - increments the inventory of a product
   * @param _productId - the product id
   * @param _inventoryAdjustment - the amount to increment
   */
  function incrementInventory(
    uint256 _productId,
    uint256 _inventoryAdjustment)
    external
    onlyCLevel
  {
    _incrementInventory(_productId, _inventoryAdjustment);
    ProductInventoryAdjusted(_productId, availableInventoryOf(_productId));
  }

  /**
  * @notice decrementInventory removes inventory levels for a product
  * @param _productId - the product id
  * @param _inventoryAdjustment - the amount to decrement
  */
  function decrementInventory(
    uint256 _productId,
    uint256 _inventoryAdjustment)
    external
    onlyCLevel
  {
    _decrementInventory(_productId, _inventoryAdjustment);
    ProductInventoryAdjusted(_productId, availableInventoryOf(_productId));
  }

  /**
  * @notice clearInventory clears the inventory of a product.
  * @dev decrementInventory verifies inventory levels, whereas this method
  * simply sets the inventory to zero. This is useful, for example, if an
  * executive wants to take a product off the market quickly. There could be a
  * race condition with decrementInventory where a product is sold, which could
  * cause the admins decrement to fail (because it may try to decrement more
  * than available).
  *
  * @param _productId - the product id
  */
  function clearInventory(uint256 _productId)
    external
    onlyCLevel
  {
    _clearInventory(_productId);
    ProductInventoryAdjusted(_productId, availableInventoryOf(_productId));
  }

  /**
  * @notice setPrice - sets the price of a product
  * @param _productId - the product id
  * @param _price - the product price
  */
  function setPrice(uint256 _productId, uint256 _price)
    external
    onlyCLevel
  {
    _setPrice(_productId, _price);
    ProductPriceChanged(_productId, _price);
  }

  /**
  * @notice setRenewable - sets if a product is renewable
  * @param _productId - the product id
  * @param _newRenewable - the new renewable setting
  */
  function setRenewable(uint256 _productId, bool _newRenewable)
    external
    onlyCLevel
  {
    _setRenewable(_productId, _newRenewable);
    ProductRenewableChanged(_productId, _newRenewable);
  }

  /** anyone **/

  /**
  * @notice The price of a product
  * @param _productId - the product id
  */
  function priceOf(uint256 _productId) public view returns (uint256) {
    return products[_productId].price;
  }

  /**
  * @notice The available inventory of a product
  * @param _productId - the product id
  */
  function availableInventoryOf(uint256 _productId) public view returns (uint256) {
    return products[_productId].available;
  }

  /**
  * @notice The total supply of a product
  * @param _productId - the product id
  */
  function totalSupplyOf(uint256 _productId) public view returns (uint256) {
    return products[_productId].supply;
  }

  /**
  * @notice The total sold of a product
  * @param _productId - the product id
  */
  function totalSold(uint256 _productId) public view returns (uint256) {
    return products[_productId].sold;
  }

  /**
  * @notice The renewal interval of a product in seconds
  * @param _productId - the product id
  */
  function intervalOf(uint256 _productId) public view returns (uint256) {
    return products[_productId].interval;
  }

  /**
  * @notice Is this product renewable?
  * @param _productId - the product id
  */
  function renewableOf(uint256 _productId) public view returns (bool) {
    return products[_productId].renewable;
  }


  /**
  * @notice The product info for a product
  * @param _productId - the product id
  */
  function productInfo(uint256 _productId)
    public
    view
    returns (uint256, uint256, uint256, uint256, bool)
  {
    return (
      priceOf(_productId),
      availableInventoryOf(_productId),
      totalSupplyOf(_productId),
      intervalOf(_productId),
      renewableOf(_productId));
  }

  /**
  * @notice Get all product ids
  */
  function getAllProductIds() public view returns (uint256[]) {
    return allProductIds;
  }

  /**
   * @notice returns the total cost to renew a product for a number of cycles
   * @dev If a product is a subscription, the interval defines the period of
   * time, in seconds, users can subscribe for. E.g. 1 month or 1 year.
   * _numCycles is the number of these intervals we want to use in the
   * calculation of the price.
   *
   * We require that the end user send precisely the amount required (instead
   * of dealing with excess refunds). This method is public so that clients can
   * read the exact amount our contract expects to receive.
   *
   * @param _productId - the product we're calculating for
   * @param _numCycles - the number of cycles to calculate for
   */
  function costForProductCycles(uint256 _productId, uint256 _numCycles)
    public
    view
    returns (uint256)
  {
    return priceOf(_productId).mul(_numCycles);
  }

  /**
   * @notice returns if this product is a subscription or not
   * @dev Some products are subscriptions and others are not. An interval of 0
   * means the product is not a subscription
   * @param _productId - the product we're checking
   */
  function isSubscriptionProduct(uint256 _productId) public view returns (bool) {
    return intervalOf(_productId) > 0;
  }

}

library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  /**
  * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

interface ERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

contract LicenseOwnership is LicenseInventory, ERC721, ERC165, ERC721Metadata, ERC721Enumerable {
  using SafeMath for uint256;

  // Total amount of tokens
  uint256 private totalTokens;

  // Mapping from token ID to owner
  mapping (uint256 => address) private tokenOwner;

  // Mapping from token ID to approved address
  mapping (uint256 => address) private tokenApprovals;

  // Mapping from owner address to operator address to approval
  mapping (address => mapping (address => bool)) private operatorApprovals;

  // Mapping from owner to list of owned token IDs
  mapping (address => uint256[]) private ownedTokens;

  // Mapping from token ID to index of the owner tokens list
  mapping(uint256 => uint256) private ownedTokensIndex;

  /*** Constants ***/
  // Configure these for your own deployment
  string public constant NAME = "Dottabot";
  string public constant SYMBOL = "DOTTA";
  string public tokenMetadataBaseURI = "https://api.dottabot.com/";

  /**
   * @notice token's name
   */
  function name() external pure returns (string) {
    return NAME;
  }

  /**
   * @notice symbols's name
   */
  function symbol() external pure returns (string) {
    return SYMBOL;
  }

  function implementsERC721() external pure returns (bool) {
    return true;
  }

  function tokenURI(uint256 _tokenId)
    external
    view
    returns (string infoUrl)
  {
    return Strings.strConcat(
      tokenMetadataBaseURI,
      Strings.uint2str(_tokenId));
  }

  function supportsInterface(
    bytes4 interfaceID) // solium-disable-line dotta/underscore-function-arguments
    external view returns (bool)
  {
    return
      interfaceID == this.supportsInterface.selector || // ERC165
      interfaceID == 0x5b5e139f || // ERC721Metadata
      interfaceID == 0x6466353c || // ERC-721 on 3/7/2018
      interfaceID == 0x780e9d63; // ERC721Enumerable
  }

  function setTokenMetadataBaseURI(string _newBaseURI) external onlyCEOOrCOO {
    tokenMetadataBaseURI = _newBaseURI;
  }

  /**
  * @notice Guarantees msg.sender is owner of the given token
  * @param _tokenId uint256 ID of the token to validate its ownership belongs to msg.sender
  */
  modifier onlyOwnerOf(uint256 _tokenId) {
    require(ownerOf(_tokenId) == msg.sender);
    _;
  }

  /**
  * @notice Gets the total amount of tokens stored by the contract
  * @return uint256 representing the total amount of tokens
  */
  function totalSupply() public view returns (uint256) {
    return totalTokens;
  }

  /**
  * @notice Enumerate valid NFTs
  * @dev Our Licenses are kept in an array and each new License-token is just
  * the next element in the array. This method is required for ERC721Enumerable
  * which may support more complicated storage schemes. However, in our case the
  * _index is the tokenId
  * @param _index A counter less than `totalSupply()`
  * @return The token identifier for the `_index`th NFT
  */
  function tokenByIndex(uint256 _index) external view returns (uint256) {
    require(_index < totalSupply());
    return _index;
  }

  /**
  * @notice Gets the balance of the specified address
  * @param _owner address to query the balance of
  * @return uint256 representing the amount owned by the passed address
  */
  function balanceOf(address _owner) public view returns (uint256) {
    require(_owner != address(0));
    return ownedTokens[_owner].length;
  }

  /**
  * @notice Gets the list of tokens owned by a given address
  * @param _owner address to query the tokens of
  * @return uint256[] representing the list of tokens owned by the passed address
  */
  function tokensOf(address _owner) public view returns (uint256[]) {
    return ownedTokens[_owner];
  }

  /**
  * @notice Enumerate NFTs assigned to an owner
  * @dev 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 The token identifier for the `_index`th NFT assigned to `_owner`,
  */
  function tokenOfOwnerByIndex(address _owner, uint256 _index)
    external
    view
    returns (uint256 _tokenId)
  {
    require(_index < balanceOf(_owner));
    return ownedTokens[_owner][_index];
  }

  /**
  * @notice Gets the owner of the specified token ID
  * @param _tokenId uint256 ID of the token to query the owner of
  * @return owner address currently marked as the owner of the given token ID
  */
  function ownerOf(uint256 _tokenId) public view returns (address) {
    address owner = tokenOwner[_tokenId];
    require(owner != address(0));
    return owner;
  }

  /**
   * @notice Gets the approved address to take ownership of a given token ID
   * @param _tokenId uint256 ID of the token to query the approval of
   * @return address currently approved to take ownership of the given token ID
   */
  function getApproved(uint256 _tokenId) public view returns (address) {
    return tokenApprovals[_tokenId];
  }

  /**
   * @notice Tells whether the msg.sender is approved to transfer the given token ID or not
   * Checks both for specific approval and operator approval
   * @param _tokenId uint256 ID of the token to query the approval of
   * @return bool whether transfer by msg.sender is approved for the given token ID or not
   */
  function isSenderApprovedFor(uint256 _tokenId) internal view returns (bool) {
    return
      ownerOf(_tokenId) == msg.sender ||
      isSpecificallyApprovedFor(msg.sender, _tokenId) ||
      isApprovedForAll(ownerOf(_tokenId), msg.sender);
  }

  /**
   * @notice Tells whether the msg.sender is approved for the given token ID or not
   * @param _asker address of asking for approval
   * @param _tokenId uint256 ID of the token to query the approval of
   * @return bool whether the msg.sender is approved for the given token ID or not
   */
  function isSpecificallyApprovedFor(address _asker, uint256 _tokenId) internal view returns (bool) {
    return getApproved(_tokenId) == _asker;
  }

  /**
   * @notice Tells whether an operator is approved by a given owner
   * @param _owner owner address which you want to query the approval of
   * @param _operator operator address which you want to query the approval of
   * @return bool whether the given operator is approved by the given owner
   */
  function isApprovedForAll(address _owner, address _operator) public view returns (bool)
  {
    return operatorApprovals[_owner][_operator];
  }

  /**
  * @notice Transfers the ownership of a given token ID to another address
  * @param _to address to receive the ownership of the given token ID
  * @param _tokenId uint256 ID of the token to be transferred
  */
  function transfer(address _to, uint256 _tokenId)
    external
    whenNotPaused
    onlyOwnerOf(_tokenId)
  {
    _clearApprovalAndTransfer(msg.sender, _to, _tokenId);
  }

  /**
  * @notice Approves another address to claim for the ownership of the given token ID
  * @param _to address to be approved for the given token ID
  * @param _tokenId uint256 ID of the token to be approved
  */
  function approve(address _to, uint256 _tokenId)
    external
    whenNotPaused
    onlyOwnerOf(_tokenId)
  {
    address owner = ownerOf(_tokenId);
    require(_to != owner);
    if (getApproved(_tokenId) != 0 || _to != 0) {
      tokenApprovals[_tokenId] = _to;
      Approval(owner, _to, _tokenId);
    }
  }

  /**
  * @notice Enable or disable approval for a third party ("operator") to manage all your assets
  * @dev Emits the ApprovalForAll event
  * @param _to Address to add to the set of authorized operators.
  * @param _approved True if the operators is approved, false to revoke approval
  */
  function setApprovalForAll(address _to, bool _approved)
    external
    whenNotPaused
  {
    if(_approved) {
      approveAll(_to);
    } else {
      disapproveAll(_to);
    }
  }

  /**
  * @notice Approves another address to claim for the ownership of any tokens owned by this account
  * @param _to address to be approved for the given token ID
  */
  function approveAll(address _to)
    public
    whenNotPaused
  {
    require(_to != msg.sender);
    require(_to != address(0));
    operatorApprovals[msg.sender][_to] = true;
    ApprovalForAll(msg.sender, _to, true);
  }

  /**
  * @notice Removes approval for another address to claim for the ownership of any
  *  tokens owned by this account.
  * @dev Note that this only removes the operator approval and
  *  does not clear any independent, specific approvals of token transfers to this address
  * @param _to address to be disapproved for the given token ID
  */
  function disapproveAll(address _to)
    public
    whenNotPaused
  {
    require(_to != msg.sender);
    delete operatorApprovals[msg.sender][_to];
    ApprovalForAll(msg.sender, _to, false);
  }

  /**
  * @notice Claims the ownership of a given token ID
  * @param _tokenId uint256 ID of the token being claimed by the msg.sender
  */
  function takeOwnership(uint256 _tokenId)
   external
   whenNotPaused
  {
    require(isSenderApprovedFor(_tokenId));
    _clearApprovalAndTransfer(ownerOf(_tokenId), msg.sender, _tokenId);
  }

  /**
  * @notice Transfer a token owned by another address, for which the calling address has
  *  previously been granted transfer approval by the owner.
  * @param _from The address that owns the token
  * @param _to The address that will take ownership of the token. Can be any address, including the caller
  * @param _tokenId The ID of the token to be transferred
  */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    public
    whenNotPaused
  {
    require(isSenderApprovedFor(_tokenId));
    require(ownerOf(_tokenId) == _from);
    _clearApprovalAndTransfer(ownerOf(_tokenId), _to, _tokenId);
  }

  /**
  * @notice Transfers the ownership of an NFT from one address to another address
  * @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. 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 _data
  )
    public
    whenNotPaused
  {
    require(_to != address(0));
    require(_isValidLicense(_tokenId));
    transferFrom(_from, _to, _tokenId);
    if (_isContract(_to)) {
      bytes4 tokenReceiverResponse = ERC721TokenReceiver(_to).onERC721Received.gas(50000)(
        _from, _tokenId, _data
      );
      require(tokenReceiverResponse == bytes4(keccak256("onERC721Received(address,uint256,bytes)")));
    }
  }

  /*
   * @notice Transfers the ownership of an NFT from one address to another address
   * @dev 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
    whenNotPaused
  {
    safeTransferFrom(_from, _to, _tokenId, "");
  }

  /**
  * @notice Mint token function
  * @param _to The address that will own the minted token
  * @param _tokenId uint256 ID of the token to be minted by the msg.sender
  */
  function _mint(address _to, uint256 _tokenId) internal {
    require(_to != address(0));
    _addToken(_to, _tokenId);
    Transfer(0x0, _to, _tokenId);
  }

  /**
  * @notice Internal function to clear current approval and transfer the ownership of a given token ID
  * @param _from address which you want to send tokens from
  * @param _to address which you want to transfer the token to
  * @param _tokenId uint256 ID of the token to be transferred
  */
  function _clearApprovalAndTransfer(address _from, address _to, uint256 _tokenId) internal {
    require(_to != address(0));
    require(_to != ownerOf(_tokenId));
    require(ownerOf(_tokenId) == _from);
    require(_isValidLicense(_tokenId));

    _clearApproval(_from, _tokenId);
    _removeToken(_from, _tokenId);
    _addToken(_to, _tokenId);
    Transfer(_from, _to, _tokenId);
  }

  /**
  * @notice Internal function to clear current approval of a given token ID
  * @param _tokenId uint256 ID of the token to be transferred
  */
  function _clearApproval(address _owner, uint256 _tokenId) private {
    require(ownerOf(_tokenId) == _owner);
    tokenApprovals[_tokenId] = 0;
    Approval(_owner, 0, _tokenId);
  }

  /**
  * @notice Internal function to add a token ID to the list of a given address
  * @param _to address representing the new owner of the given token ID
  * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
  */
  function _addToken(address _to, uint256 _tokenId) private {
    require(tokenOwner[_tokenId] == address(0));
    tokenOwner[_tokenId] = _to;
    uint256 length = balanceOf(_to);
    ownedTokens[_to].push(_tokenId);
    ownedTokensIndex[_tokenId] = length;
    totalTokens = totalTokens.add(1);
  }

  /**
  * @notice Internal function to remove a token ID from the list of a given address
  * @param _from address representing the previous owner of the given token ID
  * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
  */
  function _removeToken(address _from, uint256 _tokenId) private {
    require(ownerOf(_tokenId) == _from);

    uint256 tokenIndex = ownedTokensIndex[_tokenId];
    uint256 lastTokenIndex = balanceOf(_from).sub(1);
    uint256 lastToken = ownedTokens[_from][lastTokenIndex];

    tokenOwner[_tokenId] = 0;
    ownedTokens[_from][tokenIndex] = lastToken;
    ownedTokens[_from][lastTokenIndex] = 0;
    // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
    // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
    // the lastToken to the first position, and then dropping the element placed in the last position of the list

    ownedTokens[_from].length--;
    ownedTokensIndex[_tokenId] = 0;
    ownedTokensIndex[lastToken] = tokenIndex;
    totalTokens = totalTokens.sub(1);
  }

  function _isContract(address addr) internal view returns (bool) {
    uint size;
    assembly { size := extcodesize(addr) }
    return size > 0;
  }
}

contract LicenseSale is LicenseOwnership {
  AffiliateProgram public affiliateProgram;

  /**
   * @notice We credit affiliates for renewals that occur within this time of
   * original purchase. E.g. If this is set to 1 year, and someone subscribes to
   * a monthly plan, the affiliate will receive credits for that whole year, as
   * the user renews their plan
   */
  uint256 public renewalsCreditAffiliatesFor = 1 years;

  /** internal **/
  function _performPurchase(
    uint256 _productId,
    uint256 _numCycles,
    address _assignee,
    uint256 _attributes,
    address _affiliate)
    internal returns (uint)
  {
    _purchaseOneUnitInStock(_productId);
    return _createLicense(
      _productId,
      _numCycles,
      _assignee,
      _attributes,
      _affiliate
      );
  }

  function _createLicense(
    uint256 _productId,
    uint256 _numCycles,
    address _assignee,
    uint256 _attributes,
    address _affiliate)
    internal
    returns (uint)
  {
    // You cannot create a subscription license with zero cycles
    if(isSubscriptionProduct(_productId)) {
      require(_numCycles != 0);
    }

    // Non-subscription products have an expiration time of 0, meaning "no-expiration"
    uint256 expirationTime = isSubscriptionProduct(_productId) ?
      now.add(intervalOf(_productId).mul(_numCycles)) : // solium-disable-line security/no-block-members
      0;

    License memory _license = License({
      productId: _productId,
      attributes: _attributes,
      issuedTime: now, // solium-disable-line security/no-block-members
      expirationTime: expirationTime,
      affiliate: _affiliate
    });

    uint256 newLicenseId = licenses.push(_license) - 1; // solium-disable-line zeppelin/no-arithmetic-operations
    LicenseIssued(
      _assignee,
      msg.sender,
      newLicenseId,
      _license.productId,
      _license.attributes,
      _license.issuedTime,
      _license.expirationTime,
      _license.affiliate);
    _mint(_assignee, newLicenseId);
    return newLicenseId;
  }

  function _handleAffiliate(
    address _affiliate,
    uint256 _productId,
    uint256 _licenseId,
    uint256 _purchaseAmount)
    internal
  {
    uint256 affiliateCut = affiliateProgram.cutFor(
      _affiliate,
      _productId,
      _licenseId,
      _purchaseAmount);
    if(affiliateCut > 0) {
      require(affiliateCut < _purchaseAmount);
      affiliateProgram.credit.value(affiliateCut)(_affiliate, _licenseId);
    }
  }

  function _performRenewal(uint256 _tokenId, uint256 _numCycles) internal {
    // You cannot renew a non-expiring license
    // ... but in what scenario can this happen?
    // require(licenses[_tokenId].expirationTime != 0);
    uint256 productId = licenseProductId(_tokenId);

    // If our expiration is in the future, renewing adds time to that future expiration
    // If our expiration has passed already, then we use `now` as the base.
    uint256 renewalBaseTime = Math.max256(now, licenses[_tokenId].expirationTime);

    // We assume that the payment has been validated outside of this function
    uint256 newExpirationTime = renewalBaseTime.add(intervalOf(productId).mul(_numCycles));

    licenses[_tokenId].expirationTime = newExpirationTime;

    LicenseRenewal(
      ownerOf(_tokenId),
      msg.sender,
      _tokenId,
      productId,
      newExpirationTime
    );
  }

  function _affiliateProgramIsActive() internal view returns (bool) {
    return
      affiliateProgram != address(0) &&
      affiliateProgram.storeAddress() == address(this) &&
      !affiliateProgram.paused();
  }

  /** executives **/
  function setAffiliateProgramAddress(address _address) external onlyCEO {
    AffiliateProgram candidateContract = AffiliateProgram(_address);
    require(candidateContract.isAffiliateProgram());
    affiliateProgram = candidateContract;
  }

  function setRenewalsCreditAffiliatesFor(uint256 _newTime) external onlyCEO {
    renewalsCreditAffiliatesFor = _newTime;
  }

  function createPromotionalPurchase(
    uint256 _productId,
    uint256 _numCycles,
    address _assignee,
    uint256 _attributes
    )
    external
    onlyCEOOrCOO
    whenNotPaused
    returns (uint256)
  {
    return _performPurchase(
      _productId,
      _numCycles,
      _assignee,
      _attributes,
      address(0));
  }

  function createPromotionalRenewal(
    uint256 _tokenId,
    uint256 _numCycles
    )
    external
    onlyCEOOrCOO
    whenNotPaused
  {
    uint256 productId = licenseProductId(_tokenId);
    _requireRenewableProduct(productId);

    return _performRenewal(_tokenId, _numCycles);
  }

  /** anyone **/

  /**
  * @notice Makes a purchase of a product.
  * @dev Requires that the value sent is exactly the price of the product
  * @param _productId - the product to purchase
  * @param _numCycles - the number of cycles being purchased. This number should be `1` for non-subscription products and the number of cycles for subscriptions.
  * @param _assignee - the address to assign the purchase to (doesn't have to be msg.sender)
  * @param _affiliate - the address to of the affiliate - use address(0) if none
  */
  function purchase(
    uint256 _productId,
    uint256 _numCycles,
    address _assignee,
    address _affiliate
    )
    external
    payable
    whenNotPaused
    returns (uint256)
  {
    require(_productId != 0);
    require(_numCycles != 0);
    require(_assignee != address(0));
    // msg.value can be zero: free products are supported

    // Don't bother dealing with excess payments. Ensure the price paid is
    // accurate. No more, no less.
    require(msg.value == costForProductCycles(_productId, _numCycles));

    // Non-subscription products should send a _numCycle of 1 -- you can't buy a
    // multiple quantity of a non-subscription product with this function
    if(!isSubscriptionProduct(_productId)) {
      require(_numCycles == 1);
    }

    // this can, of course, be gamed by malicious miners. But it's adequate for our application
    // Feel free to add your own strategies for product attributes
    // solium-disable-next-line security/no-block-members, zeppelin/no-arithmetic-operations
    uint256 attributes = uint256(keccak256(block.blockhash(block.number-1)))^_productId^(uint256(_assignee));
    uint256 licenseId = _performPurchase(
      _productId,
      _numCycles,
      _assignee,
      attributes,
      _affiliate);

    if(
      priceOf(_productId) > 0 &&
      _affiliate != address(0) &&
      _affiliateProgramIsActive()
    ) {
      _handleAffiliate(
        _affiliate,
        _productId,
        licenseId,
        msg.value);
    }

    return licenseId;
  }

  /**
   * @notice Renews a subscription
   */
  function renew(
    uint256 _tokenId,
    uint256 _numCycles
    )
    external
    payable
    whenNotPaused
  {
    require(_numCycles != 0);
    require(ownerOf(_tokenId) != address(0));

    uint256 productId = licenseProductId(_tokenId);
    _requireRenewableProduct(productId);

    // No excess payments. Ensure the price paid is exactly accurate. No more,
    // no less.
    uint256 renewalCost = costForProductCycles(productId, _numCycles);
    require(msg.value == renewalCost);

    _performRenewal(_tokenId, _numCycles);

    if(
      renewalCost > 0 &&
      licenseAffiliate(_tokenId) != address(0) &&
      _affiliateProgramIsActive() &&
      licenseIssuedTime(_tokenId).add(renewalsCreditAffiliatesFor) > now
    ) {
      _handleAffiliate(
        licenseAffiliate(_tokenId),
        productId,
        _tokenId,
        msg.value);
    }
  }

}

contract LicenseCore is LicenseSale {
  address public newContractAddress;

  function LicenseCore() public {
    paused = true;

    ceoAddress = msg.sender;
    cooAddress = msg.sender;
    cfoAddress = msg.sender;
    withdrawalAddress = msg.sender;
  }

  function setNewAddress(address _v2Address) external onlyCEO whenPaused {
    newContractAddress = _v2Address;
    ContractUpgrade(_v2Address);
  }

  function() external {
    assert(false);
  }

  function unpause() public onlyCEO whenPaused {
    require(newContractAddress == address(0));
    super.unpause();
  }
}

library Strings {
  // via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
  function strConcat(string _a, string _b, string _c, string _d, string _e) internal pure returns (string) {
      bytes memory _ba = bytes(_a);
      bytes memory _bb = bytes(_b);
      bytes memory _bc = bytes(_c);
      bytes memory _bd = bytes(_d);
      bytes memory _be = bytes(_e);
      string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
      bytes memory babcde = bytes(abcde);
      uint k = 0;
      for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
      for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
      for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
      for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
      for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
      return string(babcde);
    }

    function strConcat(string _a, string _b, string _c, string _d) internal pure returns (string) {
        return strConcat(_a, _b, _c, _d, "");
    }

    function strConcat(string _a, string _b, string _c) internal pure returns (string) {
        return strConcat(_a, _b, _c, "", "");
    }

    function strConcat(string _a, string _b) internal pure returns (string) {
        return strConcat(_a, _b, "", "", "");
    }

    function uint2str(uint i) internal pure returns (string) {
        if (i == 0) return "0";
        uint j = i;
        uint len;
        while (j != 0){
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (i != 0){
            bstr[k--] = byte(48 + i % 10);
            i /= 10;
        }
        return string(bstr);
    }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[{"name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cfoAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"isSubscriptionProduct","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"approveAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ceoAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseAffiliate","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementsERC721","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseIssuedTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseInfo","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newBaseURI","type":"string"}],"name":"setTokenMetadataBaseURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newWithdrawalAddress","type":"address"}],"name":"setWithdrawalAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_numCycles","type":"uint256"}],"name":"costForProductCycles","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newCEO","type":"address"}],"name":"setCEO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newCOO","type":"address"}],"name":"setCOO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"name":"_tokenId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_numCycles","type":"uint256"},{"name":"_assignee","type":"address"},{"name":"_attributes","type":"uint256"}],"name":"createPromotionalPurchase","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_newRenewable","type":"bool"}],"name":"setRenewable","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"renewableOf","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newCFO","type":"address"}],"name":"setCFO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"disapproveAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"}],"name":"clearInventory","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"tokensOf","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdrawBalance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllProductIds","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"newContractAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_v2Address","type":"address"}],"name":"setNewAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"totalSupplyOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"products","outputs":[{"name":"id","type":"uint256"},{"name":"price","type":"uint256"},{"name":"available","type":"uint256"},{"name":"supply","type":"uint256"},{"name":"sold","type":"uint256"},{"name":"interval","type":"uint256"},{"name":"renewable","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_numCycles","type":"uint256"}],"name":"createPromotionalRenewal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"availableInventoryOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_initialPrice","type":"uint256"},{"name":"_initialInventoryQuantity","type":"uint256"},{"name":"_supply","type":"uint256"},{"name":"_interval","type":"uint256"}],"name":"createProduct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"totalSold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseProductId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"NAME","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_numCycles","type":"uint256"},{"name":"_assignee","type":"address"},{"name":"_affiliate","type":"address"}],"name":"purchase","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"cooAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"takeOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"intervalOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"affiliateProgram","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenMetadataBaseURI","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"priceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_productId","type":"uint256"}],"name":"productInfo","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setAffiliateProgramAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_numCycles","type":"uint256"}],"name":"renew","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"name":"infoUrl","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newTime","type":"uint256"}],"name":"setRenewalsCreditAffiliatesFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"allProductIds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseExpirationTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_inventoryAdjustment","type":"uint256"}],"name":"incrementInventory","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"renewalsCreditAffiliatesFor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"withdrawalAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_licenseId","type":"uint256"}],"name":"licenseAttributes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYMBOL","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_productId","type":"uint256"},{"name":"_inventoryAdjustment","type":"uint256"}],"name":"decrementInventory","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_approved","type":"address"},{"indexed":false,"name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_operator","type":"address"},{"indexed":false,"name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"price","type":"uint256"},{"indexed":false,"name":"available","type":"uint256"},{"indexed":false,"name":"supply","type":"uint256"},{"indexed":false,"name":"interval","type":"uint256"},{"indexed":false,"name":"renewable","type":"bool"}],"name":"ProductCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"available","type":"uint256"}],"name":"ProductInventoryAdjusted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"price","type":"uint256"}],"name":"ProductPriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"renewable","type":"bool"}],"name":"ProductRenewableChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"purchaser","type":"address"},{"indexed":false,"name":"licenseId","type":"uint256"},{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"attributes","type":"uint256"},{"indexed":false,"name":"issuedTime","type":"uint256"},{"indexed":false,"name":"expirationTime","type":"uint256"},{"indexed":false,"name":"affiliate","type":"address"}],"name":"LicenseIssued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"purchaser","type":"address"},{"indexed":false,"name":"licenseId","type":"uint256"},{"indexed":false,"name":"productId","type":"uint256"},{"indexed":false,"name":"expirationTime","type":"uint256"}],"name":"LicenseRenewal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newContract","type":"address"}],"name":"ContractUpgrade","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"}]

606060409081526003805460a060020a60ff02191690558051908101604052601981527f68747470733a2f2f6170692e646f747461626f742e636f6d2f000000000000006020820152600d9080516200005d929160200190620000d9565b506301e13380600f5534156200007257600080fd5b6003805460008054600160a060020a033316600160a060020a03199182168117909255600280548216831790556001805482168317905560a060020a60ff02199092167401000000000000000000000000000000000000000017919091161790556200017e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200011c57805160ff19168380011785556200014c565b828001600101855582156200014c579182015b828111156200014c5782518255916020019190600101906200012f565b506200015a9291506200015e565b5090565b6200017b91905b808211156200015a576000815560010162000165565b90565b613711806200018e6000396000f3006060604052600436106103345763ffffffff60e060020a60003504166301ffc9a781146103435780630519ce79146103775780630528bb57146103a65780630621472c146103bc57806306fdde03146103db578063081812fc14610465578063095ea7b31461047b5780630a0f81681461049d5780630e9fd199146104b05780631051db34146104c65780631411d713146104d957806318160ddd146105015780631e084558146105145780631e20363a1461056357806321b8092e1461058157806323b872dd146105a057806327597f0a146105c857806327d7874c146105e15780632ba73c15146106005780632f745c591461061f5780633ac6dd9d146106415780633f4ba83a146106695780633f4f30751461067c57806342842e0e146106975780634dac7d6f146106bf5780634e0a3379146106d55780634f6ccce7146106f457806351dabd451461070a578063533f6730146107295780635a3f26721461073f5780635c975abb146107b15780635fd8c710146107c45780636352211e146107d7578063663c01af146107ed5780636af04a571461080057806370a0823114610813578063715879881461083257806375b0d9cd146108515780637acc0b20146108675780637d0385c2146108bb5780638456cb59146108d4578063892412f0146108e757806392363a42146108fd57806393b2467e1461091f5780639425753c1461093557806395d89b411461094b578063a22cb4651461095e578063a3f4df7e14610982578063a7bf1b6c14610995578063a9059cbb146109b5578063b047fb50146109d7578063b2e6ceeb146109ea578063b369af7114610a00578063b3b4fd0f14610a16578063b5cab1ce14610a29578063b88d4fde14610a3c578063b9186d7d14610aa8578063bb119f6e14610abe578063c2b7ba3214610b05578063c475abff14610b24578063c87b56dd14610b32578063cc293aea14610b48578063dde1bbcf14610b5e578063dfbebd0714610b74578063e89b5d4b14610b8a578063e9748e5814610ba3578063e985e9c514610bb6578063f2bcd02214610bdb578063f4b272db14610bee578063f76f8d7814610c04578063f7d9757714610c17578063fe3d07e414610c30575b341561033f57600080fd5bfe5b005b341561034e57600080fd5b610363600160e060020a031960043516610c49565b604051901515815260200160405180910390f35b341561038257600080fd5b61038a610d1a565b604051600160a060020a03909116815260200160405180910390f35b34156103b157600080fd5b610363600435610d29565b34156103c757600080fd5b610341600160a060020a0360043516610d3c565b34156103e657600080fd5b6103ee610df7565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561042a578082015183820152602001610412565b50505050905090810190601f1680156104575780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561047057600080fd5b61038a600435610e39565b341561048657600080fd5b610341600160a060020a0360043516602435610e54565b34156104a857600080fd5b61038a610f51565b34156104bb57600080fd5b61038a600435610f60565b34156104d157600080fd5b610363610f94565b34156104e457600080fd5b6104ef600435610f99565b60405190815260200160405180910390f35b341561050c57600080fd5b6104ef610fc3565b341561051f57600080fd5b61052a600435610fc9565b60405194855260208501939093526040808501929092526060840152600160a060020a03909116608083015260a0909101905180910390f35b341561056e57600080fd5b6103416004803560248101910135611010565b341561058c57600080fd5b610341600160a060020a0360043516611057565b34156105ab57600080fd5b610341600160a060020a03600435811690602435166044356110a9565b34156105d357600080fd5b6104ef60043560243561110d565b34156105ec57600080fd5b610341600160a060020a036004351661112f565b341561060b57600080fd5b610341600160a060020a0360043516611181565b341561062a57600080fd5b6104ef600160a060020a03600435166024356111d3565b341561064c57600080fd5b6104ef600435602435600160a060020a0360443516606435611221565b341561067457600080fd5b610341611288565b341561068757600080fd5b61034160043560243515156112db565b34156106a257600080fd5b610341600160a060020a0360043581169060243516604435611374565b34156106ca57600080fd5b6103636004356113a5565b34156106e057600080fd5b610341600160a060020a03600435166113be565b34156106ff57600080fd5b6104ef600435611410565b341561071557600080fd5b610341600160a060020a0360043516611429565b341561073457600080fd5b6103416004356114c9565b341561074a57600080fd5b61075e600160a060020a0360043516611566565b60405160208082528190810183818151815260200191508051906020019060200280838360005b8381101561079d578082015183820152602001610785565b505050509050019250505060405180910390f35b34156107bc57600080fd5b6103636115e9565b34156107cf57600080fd5b6103416115f9565b34156107e257600080fd5b61038a60043561167f565b34156107f857600080fd5b61075e6116a3565b341561080b57600080fd5b61038a611701565b341561081e57600080fd5b6104ef600160a060020a0360043516611710565b341561083d57600080fd5b610341600160a060020a0360043516611743565b341561085c57600080fd5b6104ef6004356117d1565b341561087257600080fd5b61087d6004356117e6565b60405196875260208701959095526040808701949094526060860192909252608085015260a084015290151560c083015260e0909101905180910390f35b34156108c657600080fd5b610341600435602435611827565b34156108df57600080fd5b610341611895565b34156108f257600080fd5b6104ef60043561194d565b341561090857600080fd5b610341600435602435604435606435608435611962565b341561092a57600080fd5b6104ef6004356119ac565b341561094057600080fd5b6104ef6004356119c1565b341561095657600080fd5b6103ee6119eb565b341561096957600080fd5b610341600160a060020a03600435166024351515611a2c565b341561098d57600080fd5b6103ee611a64565b6104ef600435602435600160a060020a0360443581169060643516611a9b565b34156109c057600080fd5b610341600160a060020a0360043516602435611b96565b34156109e257600080fd5b61038a611bdf565b34156109f557600080fd5b610341600435611bee565b3415610a0b57600080fd5b6104ef600435611c2f565b3415610a2157600080fd5b61038a611c44565b3415610a3457600080fd5b6103ee611c53565b3415610a4757600080fd5b610341600160a060020a036004803582169160248035909116916044359160849060643590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650611cf195505050505050565b3415610ab357600080fd5b6104ef600435611ea6565b3415610ac957600080fd5b610ad4600435611ebb565b60405194855260208501939093526040808501929092526060840152901515608083015260a0909101905180910390f35b3415610b1057600080fd5b610341600160a060020a0360043516611ef0565b610341600435602435611f9d565b3415610b3d57600080fd5b6103ee600435612089565b3415610b5357600080fd5b61034160043561213d565b3415610b6957600080fd5b6104ef60043561215d565b3415610b7f57600080fd5b6104ef60043561217c565b3415610b9557600080fd5b6103416004356024356121a6565b3415610bae57600080fd5b6104ef612245565b3415610bc157600080fd5b610363600160a060020a036004358116906024351661224b565b3415610be657600080fd5b61038a612279565b3415610bf957600080fd5b6104ef600435612288565b3415610c0f57600080fd5b6103ee6122b2565b3415610c2257600080fd5b6103416004356024356122e9565b3415610c3b57600080fd5b610341600435602435612380565b6000600160e060020a031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001480610cac57507f5b5e139f00000000000000000000000000000000000000000000000000000000600160e060020a03198316145b80610ce057507f6466353c00000000000000000000000000000000000000000000000000000000600160e060020a03198316145b80610d1457507f780e9d6300000000000000000000000000000000000000000000000000000000600160e060020a03198316145b92915050565b600154600160a060020a031681565b600080610d3583611c2f565b1192915050565b60035460a060020a900460ff1615610d5357600080fd5b33600160a060020a031681600160a060020a031614151515610d7457600080fd5b600160a060020a0381161515610d8957600080fd5b600160a060020a033381166000818152600a602090815260408083209486168084529490915290819020805460ff191660019081179091557f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319151901515815260200160405180910390a350565b610dff613536565b60408051908101604052600881527f446f747461626f74000000000000000000000000000000000000000000000000602082015290505b90565b600090815260096020526040902054600160a060020a031690565b60035460009060a060020a900460ff1615610e6e57600080fd5b8133600160a060020a0316610e828261167f565b600160a060020a031614610e9557600080fd5b610e9e8361167f565b9150600160a060020a038481169083161415610eb957600080fd5b610ec283610e39565b600160a060020a0316151580610ee05750600160a060020a03841615155b15610f4b57600083815260096020526040908190208054600160a060020a031916600160a060020a0387811691821790925591908416907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259086905190815260200160405180910390a35b50505050565b600054600160a060020a031681565b6000600482815481101515610f7157fe5b6000918252602090912060059091020160040154600160a060020a031692915050565b600190565b6000600482815481101515610faa57fe5b9060005260206000209060050201600201549050919050565b60075490565b6000806000806000610fda866119c1565b610fe387612288565b610fec88610f99565b610ff58961217c565b610ffe8a610f60565b939a9299509097509550909350915050565b60025433600160a060020a039081169116148061103b575060005433600160a060020a039081169116145b151561104657600080fd5b611052600d8383613548565b505050565b60005433600160a060020a0390811691161461107257600080fd5b600160a060020a038116151561108757600080fd5b60038054600160a060020a031916600160a060020a0392909216919091179055565b60035460a060020a900460ff16156110c057600080fd5b6110c9816123d9565b15156110d457600080fd5b82600160a060020a03166110e78261167f565b600160a060020a0316146110fa57600080fd5b6110526111068261167f565b8383612420565b60006111288261111c85611ea6565b9063ffffffff6124fa16565b9392505050565b60005433600160a060020a0390811691161461114a57600080fd5b600160a060020a038116151561115f57600080fd5b60008054600160a060020a031916600160a060020a0392909216919091179055565b60005433600160a060020a0390811691161461119c57600080fd5b600160a060020a03811615156111b157600080fd5b60028054600160a060020a031916600160a060020a0392909216919091179055565b60006111de83611710565b82106111e957600080fd5b600160a060020a0383166000908152600b6020526040902080548390811061120d57fe5b906000526020600020900154905092915050565b60025460009033600160a060020a039081169116148061124f575060005433600160a060020a039081169116145b151561125a57600080fd5b60035460a060020a900460ff161561127157600080fd5b61127f858585856000612530565b95945050505050565b60005433600160a060020a039081169116146112a357600080fd5b60035460a060020a900460ff1615156112bb57600080fd5b601054600160a060020a0316156112d157600080fd5b6112d9612548565b565b60025433600160a060020a0390811691161480611306575060005433600160a060020a039081169116145b8061131f575060015433600160a060020a039081169116145b151561132a57600080fd5b61133482826125c7565b7f8993c82fcc9b66ce01f4e84cdf9e0c368fc46c1c20e87e9c8324eb0ab6780cf58282604051918252151560208201526040908101905180910390a15050565b60035460a060020a900460ff161561138b57600080fd5b611052838383602060405190810160405260008152611cf1565b6000908152600660208190526040909120015460ff1690565b60005433600160a060020a039081169116146113d957600080fd5b600160a060020a03811615156113ee57600080fd5b60018054600160a060020a031916600160a060020a0392909216919091179055565b600061141a610fc3565b821061142557600080fd5b5090565b60035460a060020a900460ff161561144057600080fd5b33600160a060020a031681600160a060020a03161415151561146157600080fd5b600160a060020a033381166000818152600a6020908152604080832094861680845294909152808220805460ff191690557f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31919051901515815260200160405180910390a350565b60025433600160a060020a03908116911614806114f4575060005433600160a060020a039081169116145b8061150d575060015433600160a060020a039081169116145b151561151857600080fd5b61152181612600565b7f52de58a758e06868840036921f6c180f216295e8eb79f91399b9f8edb1f64daa8161154c8361194d565b60405191825260208201526040908101905180910390a150565b61156e613536565b600b600083600160a060020a0316600160a060020a031681526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156115dd57602002820191906000526020600020905b8154815260200190600101908083116115c9575b50505050509050919050565b60035460a060020a900460ff1681565b60015433600160a060020a0390811691161480611624575060005433600160a060020a039081169116145b151561162f57600080fd5b600354600160a060020a0316151561164657600080fd5b600354600160a060020a039081169030163180156108fc0290604051600060405180830381858888f1935050505015156112d957600080fd5b600081815260086020526040812054600160a060020a0316801515610d1457600080fd5b6116ab613536565b60058054806020026020016040519081016040528092919081815260200182805480156116f757602002820191906000526020600020905b8154815260200190600101908083116116e3575b5050505050905090565b601054600160a060020a031681565b6000600160a060020a038216151561172757600080fd5b50600160a060020a03166000908152600b602052604090205490565b60005433600160a060020a0390811691161461175e57600080fd5b60035460a060020a900460ff16151561177657600080fd5b60108054600160a060020a031916600160a060020a0383161790557f450db8da6efbe9c22f2347f7c2021231df1fc58d3ae9a2fa75d39fa44619930581604051600160a060020a03909116815260200160405180910390a150565b60009081526006602052604090206003015490565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015495909601549395929491939092919060ff1687565b60025460009033600160a060020a0390811691161480611855575060005433600160a060020a039081169116145b151561186057600080fd5b60035460a060020a900460ff161561187757600080fd5b611880836119c1565b905061188b81612628565b611052838361265c565b60025433600160a060020a03908116911614806118c0575060005433600160a060020a039081169116145b806118d9575060015433600160a060020a039081169116145b15156118e457600080fd5b60035460a060020a900460ff16156118fb57600080fd5b6003805474ff0000000000000000000000000000000000000000191660a060020a1790557f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75260405160405180910390a1565b60009081526006602052604090206002015490565b60025433600160a060020a039081169116148061198d575060005433600160a060020a039081169116145b151561199857600080fd5b6119a58585858585612746565b5050505050565b60009081526006602052604090206004015490565b60006004828154811015156119d257fe5b9060005260206000209060050201600001549050919050565b6119f3613536565b60408051908101604052600581527f444f5454410000000000000000000000000000000000000000000000000000006020820152905090565b60035460a060020a900460ff1615611a4357600080fd5b8015611a5757611a5282610d3c565b611a60565b611a6082611429565b5050565b60408051908101604052600881527f446f747461626f74000000000000000000000000000000000000000000000000602082015281565b6003546000908190819060a060020a900460ff1615611ab957600080fd5b861515611ac557600080fd5b851515611ad157600080fd5b600160a060020a0385161515611ae657600080fd5b611af0878761110d565b3414611afb57600080fd5b611b0487610d29565b1515611b175760018614611b1757600080fd5b84600160a060020a031687600143034060405190815260200160405190819003902018189150611b4a8787878588612530565b90506000611b5788611ea6565b118015611b6c5750600160a060020a03841615155b8015611b7b5750611b7b6128b7565b15611b8c57611b8c848883346129b2565b9695505050505050565b60035460a060020a900460ff1615611bad57600080fd5b8033600160a060020a0316611bc18261167f565b600160a060020a031614611bd457600080fd5b611052338484612420565b600254600160a060020a031681565b60035460a060020a900460ff1615611c0557600080fd5b611c0e816123d9565b1515611c1957600080fd5b611c2c611c258261167f565b3383612420565b50565b60009081526006602052604090206005015490565b600e54600160a060020a031681565b600d8054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611ce95780601f10611cbe57610100808354040283529160200191611ce9565b820191906000526020600020905b815481529060010190602001808311611ccc57829003601f168201915b505050505081565b60035460009060a060020a900460ff1615611d0b57600080fd5b600160a060020a0384161515611d2057600080fd5b611d2983612ac5565b1515611d3457600080fd5b611d3f8585856110a9565b611d4884612ad8565b156119a55783600160a060020a031663f0b9e5ba61c3508786866040518563ffffffff1660e060020a0281526004018084600160a060020a0316600160a060020a0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611dcf578082015183820152602001611db7565b50505050905090810190601f168015611dfc5780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600088803b1515611e1c57600080fd5b87f11515611e2957600080fd5b505050506040518051905090506040517f6f6e455243373231526563656976656428616464726573732c75696e7432353681527f2c627974657329000000000000000000000000000000000000000000000000006020820152602701604051908190039020600160e060020a03198281169116146119a557600080fd5b60009081526006602052604090206001015490565b6000806000806000611ecc86611ea6565b611ed58761194d565b611ede886117d1565b611ee789611c2f565b610ffe8a6113a5565b6000805433600160a060020a03908116911614611f0c57600080fd5b5080600160a060020a03811663cd43ee996000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515611f5457600080fd5b6102c65a03f11515611f6557600080fd5b505050604051805190501515611f7a57600080fd5b600e8054600160a060020a031916600160a060020a039290921691909117905550565b600354600090819060a060020a900460ff1615611fb957600080fd5b821515611fc557600080fd5b6000611fd08561167f565b600160a060020a03161415611fe457600080fd5b611fed846119c1565b9150611ff882612628565b612002828461110d565b905034811461201057600080fd5b61201a848461265c565b60008111801561203c5750600061203085610f60565b600160a060020a031614155b801561204b575061204b6128b7565b801561207057504261206e600f5461206287610f99565b9063ffffffff612ae016565b115b15610f4b57610f4b61208185610f60565b8386346129b2565b612091613536565b610d14600d8054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561212a5780601f106120ff5761010080835404028352916020019161212a565b820191906000526020600020905b81548152906001019060200180831161210d57829003601f168201915b505050505061213884612aef565b612be3565b60005433600160a060020a0390811691161461215857600080fd5b600f55565b600580548290811061216b57fe5b600091825260209091200154905081565b600060048281548110151561218d57fe5b9060005260206000209060050201600301549050919050565b60025433600160a060020a03908116911614806121d1575060005433600160a060020a039081169116145b806121ea575060015433600160a060020a039081169116145b15156121f557600080fd5b6121ff8282612c26565b7f52de58a758e06868840036921f6c180f216295e8eb79f91399b9f8edb1f64daa8261222a8461194d565b60405191825260208201526040908101905180910390a15050565b600f5481565b600160a060020a039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b600354600160a060020a031681565b600060048281548110151561229957fe5b9060005260206000209060050201600101549050919050565b60408051908101604052600581527f444f545441000000000000000000000000000000000000000000000000000000602082015281565b60025433600160a060020a0390811691161480612314575060005433600160a060020a039081169116145b8061232d575060015433600160a060020a039081169116145b151561233857600080fd5b6123428282612cc7565b7fd63cc1ed2f6abbff2bdc8aeb9f139df953e98c6aa57ca5bfe8e1876be9e890ec828260405191825260208201526040908101905180910390a15050565b60025433600160a060020a03908116911614806123ab575060005433600160a060020a039081169116145b806123c4575060015433600160a060020a039081169116145b15156123cf57600080fd5b6121ff8282612cf0565b600033600160a060020a03166123ee8361167f565b600160a060020a0316148061240857506124083383612d42565b80610d145750610d1461241a8361167f565b3361224b565b600160a060020a038216151561243557600080fd5b61243e8161167f565b600160a060020a038381169116141561245657600080fd5b82600160a060020a03166124698261167f565b600160a060020a03161461247c57600080fd5b61248581612ac5565b151561249057600080fd5b61249a8382612d68565b6124a48382612ded565b6124ae8282612f59565b81600160a060020a031683600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a3505050565b60008083151561250d5760009150612529565b5082820282848281151561251d57fe5b041461252557fe5b8091505b5092915050565b600061253b86613013565b611b8c868686868661307f565b60005433600160a060020a0390811691161461256357600080fd5b60035460a060020a900460ff16151561257b57600080fd5b6003805474ff0000000000000000000000000000000000000000191690557fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693360405160405180910390a1565b6125d082613214565b15156125db57600080fd5b6000918252600660208190526040909220909101805460ff1916911515919091179055565b61260981613214565b151561261457600080fd5b600090815260066020526040812060020155565b80151561263457600080fd5b61263d81610d29565b151561264857600080fd5b612651816113a5565b1515611c2c57600080fd5b600080600061266a856119c1565b92506126964260048781548110151561267f57fe5b906000526020600020906005020160030154613228565b91506126b56126a88561111c86611c2f565b839063ffffffff612ae016565b9050806004868154811015156126c757fe5b90600052602060002090600502016003018190555033600160a060020a03166126ef8661167f565b600160a060020a03167feaf24094683b38939d81835f96309c60277bbc3366d51527540fe4a67b42da5a87868560405180848152602001838152602001828152602001935050505060405180910390a35050505050565b61274e6135c2565b6127578661323f565b151561276257600080fd5b8284111561276f57600080fd5b60e06040519081016040528087815260200186815260200185815260200184815260200160008152602001838152602001836000146127af5760016127b2565b60005b1515905260008781526006602052604090209091508190815181556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c0820151600691909101805460ff191691151591909117905550600580546001810161282c8382613602565b5060009182526020909120018690557f712119543ff2c643b26af29b73e263a1ae26070bc4c92e6ca2b659885654a70181518260200151836040015184606001518560a001518660c0015160405195865260208601949094526040808601939093526060850191909152608084015290151560a083015260c0909101905180910390a1505050505050565b600e54600090600160a060020a0316158015906129415750600e54600160a060020a03308116911663f2c4da936000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561291b57600080fd5b6102c65a03f1151561292c57600080fd5b50505060405180519050600160a060020a0316145b80156129ad5750600e54600160a060020a0316635c975abb6000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561299057600080fd5b6102c65a03f115156129a157600080fd5b50505060405180519050155b905090565b600e54600090600160a060020a031663e230e24686868686866040516020015260405160e060020a63ffffffff8716028152600160a060020a039094166004850152602484019290925260448301526064820152608401602060405180830381600087803b1515612a2257600080fd5b6102c65a03f11515612a3357600080fd5b505050604051805191505060008111156119a557818110612a5357600080fd5b600e54600160a060020a031663ef6506db82878660405160e060020a63ffffffff8616028152600160a060020a03909216600483015260248201526044016000604051808303818588803b1515612aa957600080fd5b6125ee5a03f11515612aba57600080fd5b505050505050505050565b6000612ad0826119c1565b151592915050565b6000903b1190565b60008282018381101561252557fe5b612af7613536565b600080612b02613536565b6000851515612b465760408051908101604052600181527f300000000000000000000000000000000000000000000000000000000000000060208201529450612bda565b8593505b8315612b6157600190920191600a84049350612b4a565b82604051805910612b6f5750595b818152601f19601f8301168101602001604052905091505060001982015b8515612bd65760001981019060f860020a6030600a8906010290839081518110612bb357fe5b906020010190600160f860020a031916908160001a905350600a86049550612b8d565b8194505b50505050919050565b612beb613536565b611128838360206040519081016040528060008152506020604051908101604052806000815250602060405190810160405260008152613252565b6000612c3183613214565b1515612c3c57600080fd5b600083815260066020526040902060020154612c5e908363ffffffff612ae016565b600084815260066020526040812060030154919250901115612cae5760008381526006602052604090206003810154600490910154612ca3908363ffffffff612ae016565b1115612cae57600080fd5b6000928352600660205260409092206002019190915550565b612cd082613214565b1515612cdb57600080fd5b60009182526006602052604090912060010155565b6000612cfb83613214565b1515612d0657600080fd5b600083815260066020526040902060020154612d28908363ffffffff6134c216565b600093845260066020526040909320600201929092555050565b600082600160a060020a0316612d5783610e39565b600160a060020a0316149392505050565b81600160a060020a0316612d7b8261167f565b600160a060020a031614612d8e57600080fd5b6000818152600960205260408082208054600160a060020a0319169055600160a060020a038416907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259084905190815260200160405180910390a35050565b600080600084600160a060020a0316612e058561167f565b600160a060020a031614612e1857600080fd5b6000848152600c60205260409020549250612e436001612e3787611710565b9063ffffffff6134c216565b600160a060020a0386166000908152600b6020526040902080549193509083908110612e6b57fe5b60009182526020808320909101548683526008825260408084208054600160a060020a0319169055600160a060020a0389168452600b90925291208054919250829185908110612eb757fe5b6000918252602080832090910192909255600160a060020a0387168152600b90915260408120805484908110612ee957fe5b6000918252602080832090910192909255600160a060020a0387168152600b90915260409020805490612f20906000198301613602565b506000848152600c60205260408082208290558282529020839055600754612f4f90600163ffffffff6134c216565b6007555050505050565b600081815260086020526040812054600160a060020a031615612f7b57600080fd5b60008281526008602052604090208054600160a060020a031916600160a060020a038516179055612fab83611710565b600160a060020a0384166000908152600b6020526040902080549192509060018101612fd78382613602565b506000918252602080832091909101849055838252600c90526040902081905560075461300b90600163ffffffff612ae016565b600755505050565b61301c81613214565b151561302757600080fd5b60006130328261194d565b1161303c57600080fd5b613047816001612cf0565b60008181526006602052604090206004015461306a90600163ffffffff612ae016565b60009182526006602052604090912060040155565b60008061308a613626565b600061309589610d29565b156130a6578715156130a657600080fd5b6130af89610d29565b6130ba5760006130d7565b6130d76130ca8961111c8c611c2f565b429063ffffffff612ae016565b925060a0604051908101604052808a815260200187815260200142815260200184815260200186600160a060020a03168152509150600160048054806001018281613122919061365f565b600092835260209092208591600502018151815560208201518160010155604082015181600201556060820151816003015560808201516004919091018054600160a060020a031916600160a060020a03928316179055929091039250503381169088167f295203a2e224d53a9e7107bf20ca4642308c1afa628268bbfe5f796412f832428385518660200151876040015188606001518960800151604051958652602086019490945260408086019390935260608501919091526080840152600160a060020a0390911660a083015260c0909101905180910390a361320887826134d4565b98975050505050505050565b600090815260066020526040902054151590565b6000818310156132385781611128565b5090919050565b6000908152600660205260409020541590565b61325a613536565b613262613536565b61326a613536565b613272613536565b61327a613536565b613282613536565b61328a613536565b613292613536565b6000808e98508d97508c96508b95508a94508451865188518a518c51010101016040518059106132bf5750595b818152601f19601f83011681016020016040529050935083925060009150600090505b885181101561333b578881815181106132f757fe5b016020015160f860020a900460f860020a0283838060010194508151811061331b57fe5b906020010190600160f860020a031916908160001a9053506001016132e2565b5060005b87518110156133985787818151811061335457fe5b016020015160f860020a900460f860020a0283838060010194508151811061337857fe5b906020010190600160f860020a031916908160001a90535060010161333f565b5060005b86518110156133f5578681815181106133b157fe5b016020015160f860020a900460f860020a028383806001019450815181106133d557fe5b906020010190600160f860020a031916908160001a90535060010161339c565b5060005b85518110156134525785818151811061340e57fe5b016020015160f860020a900460f860020a0283838060010194508151811061343257fe5b906020010190600160f860020a031916908160001a9053506001016133f9565b5060005b84518110156134af5784818151811061346b57fe5b016020015160f860020a900460f860020a0283838060010194508151811061348f57fe5b906020010190600160f860020a031916908160001a905350600101613456565b50909d9c50505050505050505050505050565b6000828211156134ce57fe5b50900390565b600160a060020a03821615156134e957600080fd5b6134f38282612f59565b81600160a060020a031660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050565b60206040519081016040526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106135895782800160ff198235161785556135b6565b828001600101855582156135b6579182015b828111156135b657823582559160200191906001019061359b565b5061142592915061368b565b60e0604051908101604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b8154818355818115116110525760008381526020902061105291810190830161368b565b60a060405190810160405280600081526020016000815260200160008152602001600081526020016000600160a060020a031681525090565b8154818355818115116110525760050281600502836000526020600020918201910161105291906136a5565b610e3691905b808211156114255760008155600101613691565b610e3691905b8082111561142557600080825560018201819055600282018190556003820155600481018054600160a060020a03191690556005016136ab5600a165627a7a723058200be6b83cce0244fc84b08c9dfa44e10341734a9c740f5d8b0e30f7d7e1a390fe0029

Swarm Source

bzzr://0be6b83cce0244fc84b08c9dfa44e10341734a9c740f5d8b0e30f7d7e1a390fe
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.