Contract 0x677f09A88B3A1FdCCfDdAB6E6cFd63dd02cBfA7C

Contract Overview

Balance:
0 Ether
Txn Hash
Method
Block
From
To
Value
0x1071a3c366f7186072dae31b9e34dec52d25d3e5f091093be329ff8a977bd9b3Purchase For45205022019-06-07 19:54:121077 days 14 hrs ago0xdd8e2548da5a992a63ae5520c6bc92c37a2bcc44 IN  0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c0 Ether0.0001511823
0x65883974acb87f5186d9a602af13cffd2eec1a70d1a9eb478ac4c0c26c5f52adPurchase For44632482019-05-28 21:19:141087 days 13 hrs ago0xe7de59378f3496a5434bbe998c28b71a72888f18 IN  0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c0 Ether0.0001371251
0x383cacf5b117935fcbf1291ef15f425e6a2bf06c55973a8c86f17799c28b67afPurchase For44627012019-05-28 19:02:291087 days 15 hrs ago0x3ca206264762caf81a8f0a843bbb850987b41e16 IN  0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c0 Ether0.0001371251
0xf68c3129b16ad5b6ac53893d3b814813e11a3c3642d06b3cc92d01333488f95cPurchase For44626912019-05-28 18:59:591087 days 15 hrs ago0xdd8e2548da5a992a63ae5520c6bc92c37a2bcc44 IN  0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c0 Ether0.0001671251
[ Download CSV Export 
Latest 9 internal transactions
Parent Txn Hash Block From To Value
0x1071a3c366f7186072dae31b9e34dec52d25d3e5f091093be329ff8a977bd9b345205022019-06-07 19:54:121077 days 14 hrs ago 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b0 Ether
0x1071a3c366f7186072dae31b9e34dec52d25d3e5f091093be329ff8a977bd9b345205022019-06-07 19:54:121077 days 14 hrs ago 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b0 Ether
0x65883974acb87f5186d9a602af13cffd2eec1a70d1a9eb478ac4c0c26c5f52ad44632482019-05-28 21:19:141087 days 13 hrs ago 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b0 Ether
0x65883974acb87f5186d9a602af13cffd2eec1a70d1a9eb478ac4c0c26c5f52ad44632482019-05-28 21:19:141087 days 13 hrs ago 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b0 Ether
0x383cacf5b117935fcbf1291ef15f425e6a2bf06c55973a8c86f17799c28b67af44627012019-05-28 19:02:291087 days 15 hrs ago 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b0 Ether
0x383cacf5b117935fcbf1291ef15f425e6a2bf06c55973a8c86f17799c28b67af44627012019-05-28 19:02:291087 days 15 hrs ago 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b0 Ether
0xf68c3129b16ad5b6ac53893d3b814813e11a3c3642d06b3cc92d01333488f95c44626912019-05-28 18:59:591087 days 15 hrs ago 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b0 Ether
0xf68c3129b16ad5b6ac53893d3b814813e11a3c3642d06b3cc92d01333488f95c44626912019-05-28 18:59:591087 days 15 hrs ago 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b0 Ether
0x1c6fdf6e715587fcf7536f9fb6930c86933dda514d5e21232e108b150f969af244626672019-05-28 18:53:591087 days 15 hrs ago 0xd8c88be5e8eb88e38e6ff5ce186d764676012b0b  Contract Creation0 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PublicLock

Compiler Version
v0.5.7+commit.6da8b019

Optimization Enabled:
Yes with 200 runs

Other Settings:
petersburg EvmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2019-05-28
*/

// File: contracts/interfaces/IERC721.sol

pragma solidity 0.5.7;

/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x80ac58cd

interface IERC721 {


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

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

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

  /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
  ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
  ///  THEY MAY BE PERMANENTLY LOST
  /// @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.
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  function transferFrom(address _from, address _to, uint _tokenId) external payable;

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

  /// @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,address,uint,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, uint _tokenId, bytes calldata data) external payable;

  /// @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, uint _tokenId) external payable;

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

  /// @notice Count all NFTs assigned to an owner
  /// @dev NFTs assigned to the zero address are considered invalid, and this
  ///  function throws for queries about the zero address.
  /// @param _owner An address for whom to query the balance
  /// @return The number of NFTs owned by `_owner`, possibly zero
  function balanceOf(address _owner) external view returns (uint);

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

  /// @notice Get the approved address for a single NFT
  /// @dev Throws if `_tokenId` is not a valid NFT
  /// @param _tokenId The NFT to find the approved address for
  /// @return The approved address for this NFT, or the zero address if there is none
  function getApproved(uint _tokenId) external view returns (address);

  /// @notice Query if an address is an authorized operator for another address
  /// @param _owner The address that owns the NFTs
  /// @param _operator The address that acts on behalf of the owner
  /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
  function isApprovedForAll(address _owner, address _operator) external view returns (bool);

  /// @notice A descriptive name for a collection of NFTs in this contract
  function name() external view returns (string memory _name);
}

// File: zos-lib/contracts/Initializable.sol

pragma solidity >=0.4.24 <0.6.0;


/**
 * @title Initializable
 *
 * @dev Helper contract to support initializer functions. To use it, replace
 * the constructor with a function that has the `initializer` modifier.
 * WARNING: Unlike constructors, initializer functions must be manually
 * invoked. This applies both to deploying an Initializable contract, as well
 * as extending an Initializable contract via inheritance.
 * WARNING: When used with inheritance, manual care must be taken to not invoke
 * a parent initializer twice, or ensure that all initializers are idempotent,
 * because this is not dealt with automatically as with constructors.
 */
contract Initializable {

  /**
   * @dev Indicates that the contract has been initialized.
   */
  bool private initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private initializing;

  /**
   * @dev Modifier to use in the initializer function of a contract.
   */
  modifier initializer() {
    require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

    bool wasInitializing = initializing;
    initializing = true;
    initialized = true;

    _;

    initializing = wasInitializing;
  }

  /// @dev Returns true if and only if the function is running in the constructor
  function isConstructor() private view returns (bool) {
    // extcodesize checks the size of the code stored in an address, and
    // address returns the current address. Since the code is still not
    // deployed when running a constructor, any checks on its code size will
    // yield zero, making it an effective way to detect if a contract is
    // under construction or not.
    uint256 cs;
    assembly { cs := extcodesize(address) }
    return cs == 0;
  }

  // Reserved storage space to allow for layout changes in the future.
  uint256[50] private ______gap;
}

// File: openzeppelin-eth/contracts/ownership/Ownable.sol

pragma solidity ^0.5.0;


/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable is Initializable {
    address private _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 initialize(address sender) public initializer {
        _owner = sender;
        emit OwnershipTransferred(address(0), _owner);
    }

    /**
     * @return the address of the owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

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

    /**
     * @return true if `msg.sender` is the owner of the contract.
     */
    function isOwner() public view returns (bool) {
        return msg.sender == _owner;
    }

    /**
     * @dev Allows the current owner to relinquish control of the contract.
     * @notice Renouncing to ownership will leave the contract without an owner.
     * It will not be possible to call the functions with the `onlyOwner`
     * modifier anymore.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @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 {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0));
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }

    uint256[50] private ______gap;
}

// File: openzeppelin-solidity/contracts/introspection/IERC165.sol

pragma solidity ^0.5.2;

/**
 * @title IERC165
 * @dev https://eips.ethereum.org/EIPS/eip-165
 */
interface IERC165 {
    /**
     * @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.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// File: openzeppelin-solidity/contracts/introspection/ERC165.sol

pragma solidity ^0.5.2;


/**
 * @title ERC165
 * @author Matt Condon (@shrugs)
 * @dev Implements ERC165 using a lookup table.
 */
contract ERC165 is IERC165 {
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
    /*
     * 0x01ffc9a7 ===
     *     bytes4(keccak256('supportsInterface(bytes4)'))
     */

    /**
     * @dev a mapping of interface id to whether or not it's supported
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    /**
     * @dev A contract implementing SupportsInterfaceWithLookup
     * implement ERC165 itself
     */
    constructor () internal {
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev implement supportsInterface(bytes4) using a lookup table
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev internal method for registering an interface
     */
    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff);
        _supportedInterfaces[interfaceId] = true;
    }
}

// File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol

pragma solidity ^0.5.2;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
contract IERC721Receiver {
    /**
     * @notice Handle the receipt of an NFT
     * @dev The ERC721 smart contract calls this function on the recipient
     * after a `safeTransfer`. This function MUST return the function selector,
     * otherwise the caller will revert the transaction. The selector to be
     * returned can be obtained as `this.onERC721Received.selector`. This
     * function MAY throw to revert and reject the transfer.
     * Note: the ERC721 contract address is always the message sender.
     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
    public returns (bytes4);
}

// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Holder.sol

pragma solidity ^0.5.2;


contract ERC721Holder is IERC721Receiver {
    function onERC721Received(address, address, uint256, bytes memory) public returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

// File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol

pragma solidity ^0.5.2;

/**
 * @title ERC20 interface
 * @dev see https://eips.ethereum.org/EIPS/eip-20
 */
interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);

    function totalSupply() external view returns (uint256);

    function balanceOf(address who) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// File: contracts/mixins/MixinFunds.sol

pragma solidity 0.5.7;



/**
 * @title An implementation of the money related functions.
 * @author HardlyDifficult (unlock-protocol.com)
 */
contract MixinFunds
{
  /**
   * The token-type that this Lock is priced in.  If 0, then use ETH, else this is
   * a ERC20 token address.
   */
  address public tokenAddress;

  constructor(
    address _tokenAddress
  ) public
  {
    require(
      _tokenAddress == address(0) || IERC20(_tokenAddress).totalSupply() > 0,
      'INVALID_TOKEN'
    );
    tokenAddress = _tokenAddress;
  }

  /**
   * Ensures that the msg.sender has paid at least the price stated.
   *
   * With ETH, this means the function originally called was `payable` and the
   * transaction included at least the amount requested.
   *
   * Security: be wary of re-entrancy when calling this function.
   */
  function _chargeAtLeast(
    uint _price
  ) internal
  {
    if(_price > 0) {
      if(tokenAddress == address(0)) {
        require(msg.value >= _price, 'NOT_ENOUGH_FUNDS');
      } else {
        IERC20 token = IERC20(tokenAddress);
        uint balanceBefore = token.balanceOf(address(this));
        token.transferFrom(msg.sender, address(this), _price);

        // There are known bugs in popular ERC20 implements which means we cannot
        // trust the return value of `transferFrom`.  This require statement ensures
        // that a transfer occurred.
        require(token.balanceOf(address(this)) > balanceBefore, 'TRANSFER_FAILED');
      }
    }
  }

  /**
   * Transfers funds from the contract to the account provided.
   *
   * Security: be wary of re-entrancy when calling this function.
   */
  function _transfer(
    address _to,
    uint _amount
  ) internal
  {
    if(_amount > 0) {
      if(tokenAddress == address(0)) {
        address(uint160(_to)).transfer(_amount);
      } else {
        IERC20 token = IERC20(tokenAddress);
        uint balanceBefore = token.balanceOf(_to);
        token.transfer(_to, _amount);

        // There are known bugs in popular ERC20 implements which means we cannot
        // trust the return value of `transferFrom`.  This require statement ensures
        // that a transfer occurred.
        require(token.balanceOf(_to) > balanceBefore, 'TRANSFER_FAILED');
      }
    }
  }

  /**
   * Gets the current balance of the account provided.
   */
  function _getBalance(
    address _account
  ) internal view
    returns (uint)
  {
    if(tokenAddress == address(0)) {
      return _account.balance;
    } else {
      return IERC20(tokenAddress).balanceOf(_account);
    }
  }
}

// File: contracts/mixins/MixinDisableAndDestroy.sol

pragma solidity 0.5.7;




/**
 * @title Mixin allowing the Lock owner to disable a Lock (preventing new purchases)
 * and then destroy it.
 * @author HardlyDifficult
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */
contract MixinDisableAndDestroy is
  IERC721,
  Ownable,
  MixinFunds
{
  // Used to disable payable functions when deprecating an old lock
  bool public isAlive;

  event Destroy(
    uint balance,
    address indexed owner
  );

  event Disable();

  constructor(
  ) internal
  {
    isAlive = true;
  }

  // Only allow usage when contract is Alive
  modifier onlyIfAlive() {
    require(isAlive, 'LOCK_DEPRECATED');
    _;
  }

  /**
  * @dev Used to disable lock before migrating keys and/or destroying contract
   */
  function disableLock()
    external
    onlyOwner
    onlyIfAlive
  {
    emit Disable();
    isAlive = false;
  }

  /**
  * @dev Used to clean up old lock contracts from the blockchain
  * TODO: add a check to ensure all keys are INVALID!
   */
  function destroyLock()
    external
    onlyOwner
  {
    require(isAlive == false, 'DISABLE_FIRST');

    emit Destroy(address(this).balance, msg.sender);

    // this will send any ETH or ERC20 held by the lock to the owner
    _transfer(msg.sender, _getBalance(address(this)));
    selfdestruct(msg.sender);

    // Note we don't clean up the `locks` data in Unlock.sol as it should not be necessary
    // and leaves some data behind ('Unlock.LockBalances') which may be helpful.
  }

}

// File: contracts/interfaces/IUnlock.sol

pragma solidity 0.5.7;


/**
 * @title The Unlock Interface
 * @author Nick Furfaro (unlock-protocol.com)
**/

interface IUnlock {


  // Events
  event NewLock(
    address indexed lockOwner,
    address indexed newLockAddress
  );

  event NewTokenURI(
    string tokenURI
  );

  event NewGlobalTokenSymbol(
    string tokenSymbol
  );

  // Use initialize instead of a constructor to support proxies (for upgradeability via zos).
  function initialize(address _owner) external;

  /**
  * @dev Create lock
  * This deploys a lock for a creator. It also keeps track of the deployed lock.
  * @param _tokenAddress set to the ERC20 token address, or 0 for ETH.
  */
  function createLock(
    uint _expirationDuration,
    address _tokenAddress,
    uint _keyPrice,
    uint _maxNumberOfKeys,
    string calldata _lockName
  ) external;

    /**
   * This function keeps track of the added GDP, as well as grants of discount tokens
   * to the referrer, if applicable.
   * The number of discount tokens granted is based on the value of the referal,
   * the current growth rate and the lock's discount token distribution rate
   * This function is invoked by a previously deployed lock only.
   */
  function recordKeyPurchase(
    uint _value,
    address _referrer // solhint-disable-line no-unused-vars
  )
    external;

    /**
   * This function will keep track of consumed discounts by a given user.
   * It will also grant discount tokens to the creator who is granting the discount based on the
   * amount of discount and compensation rate.
   * This function is invoked by a previously deployed lock only.
   */
  function recordConsumedDiscount(
    uint _discount,
    uint _tokens // solhint-disable-line no-unused-vars
  )
    external;

    /**
   * This function returns the discount available for a user, when purchasing a
   * a key from a lock.
   * This does not modify the state. It returns both the discount and the number of tokens
   * consumed to grant that discount.
   */
  function computeAvailableDiscountFor(
    address _purchaser, // solhint-disable-line no-unused-vars
    uint _keyPrice // solhint-disable-line no-unused-vars
  )
    external
    view
    returns (uint discount, uint tokens);

  // Function to read the globalTokenURI field.
  function getGlobalBaseTokenURI()
    external
    view
    returns (string memory);

  /** Function to set the globalTokenURI field.
   *  Should throw if called by other than owner
   */
  function setGlobalBaseTokenURI(
    string calldata _URI
  )
    external;

  // Function to read the globalTokenSymbol field.
  function getGlobalTokenSymbol()
    external
    view
    returns (string memory);

  /** Function to set the globalTokenSymbol field.
   *  Should throw if called by other than owner.
   */
  function setGlobalTokenSymbol(
    string calldata _symbol
  )
    external;

}

// File: contracts/mixins/MixinLockCore.sol

pragma solidity 0.5.7;






/**
 * @title Mixin for core lock data and functions.
 * @author HardlyDifficult
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */
contract MixinLockCore is
  Ownable,
  MixinFunds,
  MixinDisableAndDestroy
{
  event PriceChanged(
    uint oldKeyPrice,
    uint keyPrice
  );

  event Withdrawal(
    address indexed _sender,
    uint _amount
  );

  // Unlock Protocol address
  // TODO: should we make that private/internal?
  IUnlock public unlockProtocol;

  // Duration in seconds for which the keys are valid, after creation
  // should we take a smaller type use less gas?
  // TODO: add support for a timestamp instead of duration
  uint public expirationDuration;

  // price in wei of the next key
  // TODO: allow support for a keyPriceCalculator which could set prices dynamically
  uint public keyPrice;

  // Max number of keys sold if the keyReleaseMechanism is public
  uint public maxNumberOfKeys;

  // A count of how many new key purchases there have been
  uint public numberOfKeysSold;

  // Ensure that the Lock has not sold all of its keys.
  modifier notSoldOut() {
    require(maxNumberOfKeys > numberOfKeysSold, 'LOCK_SOLD_OUT');
    _;
  }

  constructor(
    uint _expirationDuration,
    uint _keyPrice,
    uint _maxNumberOfKeys
  ) internal
  {
    require(_expirationDuration <= 100 * 365 * 24 * 60 * 60, 'MAX_EXPIRATION_100_YEARS');
    unlockProtocol = IUnlock(msg.sender); // Make sure we link back to Unlock's smart contract.
    expirationDuration = _expirationDuration;
    keyPrice = _keyPrice;
    maxNumberOfKeys = _maxNumberOfKeys;
  }

  /**
   * @dev Called by owner to withdraw all funds from the lock.
   * TODO: consider allowing anybody to trigger this as long as it goes to owner anyway?
   */
  function withdraw()
    external
    onlyOwner
  {
    uint balance = _getBalance(address(this));
    require(balance > 0, 'NOT_ENOUGH_FUNDS');
    // Security: re-entrancy not a risk as this is the last line of an external function
    _withdraw(balance);
  }

  /**
   * @dev Called by owner to partially withdraw funds from the lock.
   * TODO: consider allowing anybody to trigger this as long as it goes to owner anyway?
   */
  function partialWithdraw(uint _amount)
    external
    onlyOwner
  {
    require(_amount > 0, 'GREATER_THAN_ZERO');
    uint balance = _getBalance(address(this));
    require(balance >= _amount, 'NOT_ENOUGH_FUNDS');
    // Security: re-entrancy not a risk as this is the last line of an external function
    _withdraw(_amount);
  }

  /**
   * A function which lets the owner of the lock to change the price for future purchases.
   */
  function updateKeyPrice(
    uint _keyPrice
  )
    external
    onlyOwner
    onlyIfAlive
  {
    uint oldKeyPrice = keyPrice;
    keyPrice = _keyPrice;
    emit PriceChanged(oldKeyPrice, keyPrice);
  }

  /**
   * Public function which returns the total number of unique keys sold (both
   * expired and valid)
   */
  function totalSupply()
    public
    view
    returns (uint)
  {
    return numberOfKeysSold;
  }

  /**
   * @dev private version of the withdraw function which handles all withdrawals from the lock.
   *
   * Security: Be wary of re-entrancy when calling this.
   */
  function _withdraw(uint _amount)
    private
  {
    _transfer(Ownable.owner(), _amount);
    emit Withdrawal(msg.sender, _amount);
  }
}

// File: contracts/mixins/MixinKeys.sol

pragma solidity 0.5.7;




/**
 * @title Mixin for managing `Key` data.
 * @author HardlyDifficult
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */
contract MixinKeys is
  Ownable,
  MixinLockCore
{
  // The struct for a key
  struct Key {
    uint tokenId;
    uint expirationTimestamp;
  }

  // Called when the Lock owner expires a user's Key
  event ExpireKey(uint tokenId);

  // Keys
  // Each owner can have at most exactly one key
  // TODO: could we use public here? (this could be confusing though because it getter will
  // return 0 values when missing a key)
  mapping (address => Key) private keyByOwner;

  // Each tokenId can have at most exactly one owner at a time.
  // Returns 0 if the token does not exist
  // TODO: once we decouple tokenId from owner address (incl in js), then we can consider
  // merging this with numberOfKeysSold into an array instead.
  mapping (uint => address) private ownerByTokenId;

  // Addresses of owners are also stored in an array.
  // Addresses are never removed by design to avoid abuses around referals
  address[] public owners;

  // Ensures that an owner owns or has owned a key in the past
  modifier ownsOrHasOwnedKey(
    address _owner
  ) {
    require(
      keyByOwner[_owner].expirationTimestamp > 0, 'HAS_NEVER_OWNED_KEY'
    );
    _;
  }

  // Ensures that an owner has a valid key
  modifier hasValidKey(
    address _owner
  ) {
    require(
      getHasValidKey(_owner), 'KEY_NOT_VALID'
    );
    _;
  }

  // Ensures that a key has an owner
  modifier isKey(
    uint _tokenId
  ) {
    require(
      ownerByTokenId[_tokenId] != address(0), 'NO_SUCH_KEY'
    );
    _;
  }

  // Ensure that the caller owns the key
  modifier onlyKeyOwner(
    uint _tokenId
  ) {
    require(
      isKeyOwner(_tokenId, msg.sender), 'ONLY_KEY_OWNER'
    );
    _;
  }

  /**
   * A function which lets the owner of the lock expire a users' key.
   */
  function expireKeyFor(
    address _owner
  )
    public
    onlyOwner
    hasValidKey(_owner)
  {
    Key storage key = keyByOwner[_owner];
    key.expirationTimestamp = block.timestamp; // Effectively expiring the key
    emit ExpireKey(key.tokenId);
  }

  /**
   * In the specific case of a Lock, each owner can own only at most 1 key.
   * @return The number of NFTs owned by `_owner`, either 0 or 1.
  */
  function balanceOf(
    address _owner
  )
    external
    view
    returns (uint)
  {
    require(_owner != address(0), 'INVALID_ADDRESS');
    return getHasValidKey(_owner) ? 1 : 0;
  }

  /**
   * Checks if the user has a non-expired key.
   */
  function getHasValidKey(
    address _owner
  )
    public
    view
    returns (bool)
  {
    return keyByOwner[_owner].expirationTimestamp > block.timestamp;
  }

  /**
   * @notice Find the tokenId for a given user
   * @return The tokenId of the NFT, else revert
  */
  function getTokenIdFor(
    address _account
  )
    external
    view
    hasValidKey(_account)
    returns (uint)
  {
    return keyByOwner[_account].tokenId;
  }

 /**
  * A function which returns a subset of the keys for this Lock as an array
  * @param _page the page of key owners requested when faceted by page size
  * @param _pageSize the number of Key Owners requested per page
  */
  function getOwnersByPage(uint _page, uint _pageSize)
    public
    view
    returns (address[] memory)
  {
    require(owners.length > 0, 'NO_OUTSTANDING_KEYS');
    uint pageSize = _pageSize;
    uint _startIndex = _page * pageSize;
    uint endOfPageIndex;

    if (_startIndex + pageSize > owners.length) {
      endOfPageIndex = owners.length;
      pageSize = owners.length - _startIndex;
    } else {
      endOfPageIndex = (_startIndex + pageSize);
    }

    // new temp in-memory array to hold pageSize number of requested owners:
    address[] memory ownersByPage = new address[](pageSize);
    uint pageIndex = 0;

    // Build the requested set of owners into a new temporary array:
    for (uint i = _startIndex; i < endOfPageIndex; i++) {
      ownersByPage[pageIndex] = owners[i];
      pageIndex++;
    }

    return ownersByPage;
  }

  /**
   * Checks if the given address owns the given tokenId.
   */
  function isKeyOwner(
    uint _tokenId,
    address _owner
  ) public view
    returns (bool)
  {
    return ownerByTokenId[_tokenId] == _owner;
  }

  /**
  * @dev Returns the key's ExpirationTimestamp field for a given owner.
  * @param _owner address of the user for whom we search the key
  */
  function keyExpirationTimestampFor(
    address _owner
  )
    public view
    ownsOrHasOwnedKey(_owner)
    returns (uint timestamp)
  {
    return keyByOwner[_owner].expirationTimestamp;
  }

  /**
   * Public function which returns the total number of unique owners (both expired
   * and valid).  This may be larger than totalSupply.
   */
  function numberOfOwners()
    public
    view
    returns (uint)
  {
    return owners.length;
  }

  /**
   * @notice ERC721: Find the owner of an NFT
   * @return The address of the owner of the NFT, if applicable
  */
  function ownerOf(
    uint _tokenId
  )
    public view
    isKey(_tokenId)
    returns (address)
  {
    return ownerByTokenId[_tokenId];
  }

  /**
   * Assigns the key a new tokenId (from numberOfKeysSold) if it does not already have
   * one assigned.
   */
  function _assignNewTokenId(
    Key storage _key
  ) internal
  {
    if (_key.tokenId == 0) {
      // This is a brand new owner, else an owner of an expired key buying an extension.
      // We increment the tokenId counter
      numberOfKeysSold++;
      // we assign the incremented `numberOfKeysSold` as the tokenId for the new key
      _key.tokenId = numberOfKeysSold;
    }
  }

  /**
   * Records the owner of a given tokenId
   */
  function _recordOwner(
    address _owner,
    uint _tokenId
  ) internal
  {
    if (ownerByTokenId[_tokenId] != _owner) {
      // TODO: this may include duplicate entries
      owners.push(_owner);
      // We register the owner of the tokenID
      ownerByTokenId[_tokenId] = _owner;
    }
  }

  /**
   * Returns the Key struct for the given owner.
   */
  function _getKeyFor(
    address _owner
  ) internal view
    returns (Key storage)
  {
    return keyByOwner[_owner];
  }
}

// File: contracts/mixins/MixinApproval.sol

pragma solidity 0.5.7;





/**
 * @title Mixin for the Approval related functions needed to meet the ERC721
 * standard.
 * @author HardlyDifficult
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */
contract MixinApproval is
  IERC721,
  MixinDisableAndDestroy,
  MixinKeys
{
  // Keeping track of approved transfers
  // This is a mapping of addresses which have approved
  // the transfer of a key to another address where their key can be transfered
  // Note: the approver may actually NOT have a key... and there can only
  // be a single approved beneficiary
  // Note 2: for transfer, both addresses will be different
  // Note 3: for sales (new keys on restricted locks), both addresses will be the same
  mapping (uint => address) private approved;

  // Keeping track of approved operators for a Key owner.
  // Since an owner can have up to 1 Key, this is similiar to above
  // but the approval does not reset when a transfer occurs.
  mapping (address => mapping (address => bool)) private ownerToOperatorApproved;

  // Ensure that the caller has a key
  // or that the caller has been approved
  // for ownership of that key
  modifier onlyKeyOwnerOrApproved(
    uint _tokenId
  ) {
    require(
      isKeyOwner(_tokenId, msg.sender) ||
        _isApproved(_tokenId, msg.sender) ||
        isApprovedForAll(ownerOf(_tokenId), msg.sender),
      'ONLY_KEY_OWNER_OR_APPROVED');
    _;
  }

  /**
   * This approves _approved to get ownership of _tokenId.
   * Note: that since this is used for both purchase and transfer approvals
   * the approved token may not exist.
   */
  function approve(
    address _approved,
    uint _tokenId
  )
    external
    payable
    onlyIfAlive
    onlyKeyOwnerOrApproved(_tokenId)
  {
    require(msg.sender != _approved, 'APPROVE_SELF');

    approved[_tokenId] = _approved;
    emit Approval(ownerOf(_tokenId), _approved, _tokenId);
  }

  /**
   * @dev Sets or unsets the approval of a given operator
   * An operator is allowed to transfer all tokens of the sender on their behalf
   * @param _to operator address to set the approval
   * @param _approved representing the status of the approval to be set
   */
  function setApprovalForAll(
    address _to,
    bool _approved
  ) external
    onlyIfAlive
  {
    require(_to != msg.sender, 'APPROVE_SELF');
    ownerToOperatorApproved[msg.sender][_to] = _approved;
    emit ApprovalForAll(msg.sender, _to, _approved);
  }

  /**
   * external version
   * Will return the approved recipient for a key, if any.
   */
  function getApproved(
    uint _tokenId
  )
    external
    view
    returns (address)
  {
    return _getApproved(_tokenId);
  }

  /**
   * @dev 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 ownerToOperatorApproved[_owner][_operator];
  }

  /**
   * @dev Checks if the given user is approved to transfer the tokenId.
   */
  function _isApproved(
    uint _tokenId,
    address _user
  ) internal view
    returns (bool)
  {
    return approved[_tokenId] == _user;
  }

  /**
   * Will return the approved recipient for a key transfer or ownership.
   * Note: this does not check that a corresponding key
   * actually exists.
   */
  function _getApproved(
    uint _tokenId
  )
    internal
    view
    returns (address)
  {
    address approvedRecipient = approved[_tokenId];
    require(approvedRecipient != address(0), 'NONE_APPROVED');
    return approvedRecipient;
  }

  /**
   * @dev Function to clear current approval of a given token ID
   * @param _tokenId uint256 ID of the token to be transferred
   */
  function _clearApproval(
    uint256 _tokenId
  ) internal
  {
    if (approved[_tokenId] != address(0)) {
      approved[_tokenId] = address(0);
    }
  }
}

// File: contracts/mixins/MixinGrantKeys.sol

pragma solidity 0.5.7;





/**
 * @title Mixin allowing the Lock owner to grant / gift keys to users.
 * @author HardlyDifficult
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */
contract MixinGrantKeys is
  IERC721,
  Ownable,
  MixinKeys
{
  /**
   * Allows the Lock owner to give a user a key with no charge.
   */
  function grantKey(
    address _recipient,
    uint _expirationTimestamp
  ) external
    onlyOwner
  {
    _grantKey(_recipient, _expirationTimestamp);
  }

  /**
   * Allows the Lock owner to give a collection of users a key with no charge.
   * All keys granted have the same expiration date.
   */
  function grantKeys(
    address[] calldata _recipients,
    uint _expirationTimestamp
  ) external
    onlyOwner
  {
    for(uint i = 0; i < _recipients.length; i++) {
      _grantKey(_recipients[i], _expirationTimestamp);
    }
  }

  /**
   * Allows the Lock owner to give a collection of users a key with no charge.
   * Each key may be assigned a different expiration date.
   */
  function grantKeys(
    address[] calldata _recipients,
    uint[] calldata _expirationTimestamps
  ) external
    onlyOwner
  {
    for(uint i = 0; i < _recipients.length; i++) {
      _grantKey(_recipients[i], _expirationTimestamps[i]);
    }
  }

  /**
   * Give a key to the given user
   */
  function _grantKey(
    address _recipient,
    uint _expirationTimestamp
  ) private
  {
    require(_recipient != address(0), 'INVALID_ADDRESS');

    Key storage toKey = _getKeyFor(_recipient);
    require(_expirationTimestamp > toKey.expirationTimestamp, 'ALREADY_OWNS_KEY');

    _assignNewTokenId(toKey);
    _recordOwner(_recipient, toKey.tokenId);
    toKey.expirationTimestamp = _expirationTimestamp;

    // trigger event
    emit Transfer(
      address(0), // This is a creation.
      _recipient,
      toKey.tokenId
    );
  }
}

// File: contracts/UnlockUtils.sol

pragma solidity 0.5.7;

// This contract provides some utility methods for use with the unlock protocol smart contracts.
// Borrowed from:
// https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol#L943

contract UnlockUtils {

  function strConcat(
    string memory _a,
    string memory _b,
    string memory _c,
    string memory _d
  ) public
    pure
    returns (string memory _concatenatedString)
  {
    bytes memory _ba = bytes(_a);
    bytes memory _bb = bytes(_b);
    bytes memory _bc = bytes(_c);
    bytes memory _bd = bytes(_d);
    string memory abcd = new string(_ba.length + _bb.length + _bc.length + _bd.length);
    bytes memory babcd = bytes(abcd);
    uint k = 0;
    uint i = 0;
    for (i = 0; i < _ba.length; i++) {
      babcd[k++] = _ba[i];
    }
    for (i = 0; i < _bb.length; i++) {
      babcd[k++] = _bb[i];
    }
    for (i = 0; i < _bc.length; i++) {
      babcd[k++] = _bc[i];
    }
    for (i = 0; i < _bd.length; i++) {
      babcd[k++] = _bd[i];
    }
    return string(babcd);
  }

  function uint2Str(
    uint _i
  ) public
    pure
    returns (string memory _uintAsString)
  {
    // make a copy of the param to avoid security/no-assign-params error
    uint c = _i;
    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 (c != 0) {
      bstr[k--] = byte(uint8(48 + c % 10));
      c /= 10;
    }
    return string(bstr);
  }

  function address2Str(
    address _addr
  ) public
    pure
    returns(string memory)
  {
    bytes32 value = bytes32(uint256(_addr));
    bytes memory alphabet = '0123456789abcdef';
    bytes memory str = new bytes(42);
    str[0] = '0';
    str[1] = 'x';
    for (uint i = 0; i < 20; i++) {
      str[2+i*2] = alphabet[uint8(value[i + 12] >> 4)];
      str[3+i*2] = alphabet[uint8(value[i + 12] & 0x0f)];
    }
    return string(str);
  }
}

// File: contracts/mixins/MixinLockMetadata.sol

pragma solidity 0.5.7;







/**
 * @title Mixin for metadata about the Lock.
 * @author HardlyDifficult
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */
contract MixinLockMetadata is
  IERC721,
  ERC165,
  Ownable,
  MixinLockCore,
  UnlockUtils,
  MixinKeys
{
  /// A descriptive name for a collection of NFTs in this contract.Defaults to "Unlock-Protocol" but is settable by lock owner
  string private lockName;

  /// An abbreviated name for NFTs in this contract. Defaults to "KEY" but is settable by lock owner
  string private lockSymbol;

  // the base Token URI for this Lock. If not set by lock owner, the global URI stored in Unlock is used.
  string private baseTokenURI;

  event NewLockSymbol(
    string symbol
  );

  constructor(
    string memory _lockName
  ) internal
  {
    lockName = _lockName;
    // registering the optional erc721 metadata interface with ERC165.sol using
    // the ID specified in the standard: https://eips.ethereum.org/EIPS/eip-721
    _registerInterface(0x5b5e139f);
  }

  /**
   * Allows the Lock owner to assign a descriptive name for this Lock.
   */
  function updateLockName(
    string calldata _lockName
  ) external
    onlyOwner
  {
    lockName = _lockName;
  }

  /**
    * @dev Gets the token name
    * @return string representing the token name
    */
  function name(
  ) external view
    returns (string memory)
  {
    return lockName;
  }

  /**
   * Allows the Lock owner to assign a Symbol for this Lock.
   */
  function updateLockSymbol(
    string calldata _lockSymbol
  ) external
    onlyOwner
  {
    lockSymbol = _lockSymbol;
    emit NewLockSymbol(_lockSymbol);
  }

  /**
    * @dev Gets the token symbol
    * @return string representing the token name
    */
  function symbol()
    external view
    returns(string memory)
  {
    if(bytes(lockSymbol).length == 0) {
      return unlockProtocol.getGlobalTokenSymbol();
    } else {
      return lockSymbol;
    }
  }

  /**
   * Allows the Lock owner to update the baseTokenURI for this Lock.
   */
  function setBaseTokenURI(
    string calldata _baseTokenURI
  ) external
    onlyOwner
  {
    baseTokenURI = _baseTokenURI;
  }

  /**  @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".
   * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
   */
  function tokenURI(
    uint256 _tokenId
  ) external
    view
    isKey(_tokenId)
    returns(string memory)
  {
    string memory URI;
    if(bytes(baseTokenURI).length == 0) {
      URI = unlockProtocol.getGlobalBaseTokenURI();
    } else {
      URI = baseTokenURI;
    }

    return UnlockUtils.strConcat(
      URI,
      UnlockUtils.address2Str(address(this)),
      '/',
      UnlockUtils.uint2Str(_tokenId)
    );
  }
}

// File: contracts/mixins/MixinNoFallback.sol

pragma solidity 0.5.7;


/**
 * @title Mixin for the fallback function implementation, which simply reverts.
 * @author HardlyDifficult
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */
contract MixinNoFallback
{
  /**
   * @dev the fallback function should not be used.  This explicitly reverts
   * to ensure it's never used.
   */
  function()
    external
  {
    revert('NO_FALLBACK');
  }
}

// File: openzeppelin-solidity/contracts/math/SafeMath.sol

pragma solidity ^0.5.2;

/**
 * @title SafeMath
 * @dev Unsigned math operations with safety checks that revert on error
 */
library SafeMath {
    /**
     * @dev Multiplies two unsigned integers, reverts on overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b);

        return c;
    }

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

        return c;
    }

    /**
     * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Adds two unsigned integers, reverts on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);

        return c;
    }

    /**
     * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
     * reverts when dividing by zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}

// File: contracts/mixins/MixinPurchase.sol

pragma solidity 0.5.7;







/**
 * @title Mixin for the purchase-related functions.
 * @author HardlyDifficult
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */
contract MixinPurchase is
  MixinFunds,
  MixinDisableAndDestroy,
  MixinLockCore,
  MixinKeys
{
  using SafeMath for uint;

  /**
  * @dev Purchase function, public version, with no referrer.
  * @param _recipient address of the recipient of the purchased key
  */
  function purchaseFor(
    address _recipient
  )
    external
    payable
    onlyIfAlive
  {
    return _purchaseFor(_recipient, address(0));
  }

  /**
  * @dev Purchase function, public version, with referrer.
  * @param _recipient address of the recipient of the purchased key
  * @param _referrer address of the user making the referral
  */
  function purchaseForFrom(
    address _recipient,
    address _referrer
  )
    external
    payable
    onlyIfAlive
    hasValidKey(_referrer)
  {
    return _purchaseFor(_recipient, _referrer);
  }

  /**
  * @dev Purchase function: this lets a user purchase a key from the lock for another user
  * @param _recipient address of the recipient of the purchased key
  * This will fail if
  *  - the keyReleaseMechanism is private
  *  - the keyReleaseMechanism is Approved and the recipient has not been previously approved
  *  - the amount value is smaller than the price
  *  - the recipient already owns a key
  * TODO: next version of solidity will allow for message to be added to require.
  */
  function _purchaseFor(
    address _recipient,
    address _referrer
  )
    private
    notSoldOut()
  { // solhint-disable-line function-max-lines
    require(_recipient != address(0), 'INVALID_ADDRESS');

    // Let's get the actual price for the key from the Unlock smart contract
    uint discount;
    uint tokens;
    uint inMemoryKeyPrice = keyPrice;
    (discount, tokens) = unlockProtocol.computeAvailableDiscountFor(_recipient, inMemoryKeyPrice);
    uint netPrice = inMemoryKeyPrice;
    if (discount > inMemoryKeyPrice) {
      netPrice = 0;
    } else {
      // SafeSub not required as the if statement already confirmed `inMemoryKeyPrice - discount` cannot underflow
      netPrice = inMemoryKeyPrice - discount;
    }

    // We explicitly allow for greater amounts of ETH to allow 'donations'
    _chargeAtLeast(netPrice);

    // Assign the key
    Key storage toKey = _getKeyFor(_recipient);
    uint previousExpiration = toKey.expirationTimestamp;
    if (toKey.tokenId == 0) {
      _assignNewTokenId(toKey);
      _recordOwner(_recipient, toKey.tokenId);
      // SafeAdd is not required here since expirationDuration is capped to a tiny value
      // (relative to the size of a uint)
      toKey.expirationTimestamp = block.timestamp + expirationDuration;
    } else {
      // This is an existing owner trying to extend their key
      toKey.expirationTimestamp = previousExpiration.add(expirationDuration);
    }

    if (discount > 0) {
      unlockProtocol.recordConsumedDiscount(discount, tokens);
    }

    unlockProtocol.recordKeyPurchase(netPrice, _referrer);

    // trigger event
    emit Transfer(
      address(0), // This is a creation.
      _recipient,
      numberOfKeysSold
    );
  }
}

// File: openzeppelin-solidity/contracts/cryptography/ECDSA.sol

pragma solidity ^0.5.2;

/**
 * @title Elliptic curve signature operations
 * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
 * TODO Remove this library once solidity supports passing a signature to ecrecover.
 * See https://github.com/ethereum/solidity/issues/864
 */

library ECDSA {
    /**
     * @dev Recover signer address from a message by using their signature
     * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
     * @param signature bytes signature, the signature is generated using web3.eth.sign()
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Check the signature length
        if (signature.length != 65) {
            return (address(0));
        }

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

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

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

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

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

    /**
     * toEthSignedMessageHash
     * @dev prefix a bytes32 value with "\x19Ethereum Signed Message:"
     * and hash the result
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }
}

// File: contracts/mixins/MixinRefunds.sol

pragma solidity 0.5.7;








contract MixinRefunds is
  Ownable,
  MixinFunds,
  MixinLockCore,
  MixinKeys
{
  using SafeMath for uint;

  // CancelAndRefund will return funds based on time remaining minus this penalty.
  // This is calculated as `proRatedRefund * refundPenaltyNumerator / refundPenaltyDenominator`.
  uint public refundPenaltyNumerator = 1;
  uint public refundPenaltyDenominator = 10;

  // Stores a nonce per user to use for signed messages
  mapping(address => uint) public keyOwnerToNonce;

  event CancelKey(
    uint indexed tokenId,
    address indexed owner,
    address indexed sendTo,
    uint refund
  );

  event RefundPenaltyChanged(
    uint oldRefundPenaltyNumerator,
    uint oldRefundPenaltyDenominator,
    uint refundPenaltyNumerator,
    uint refundPenaltyDenominator
  );

  /**
   * @dev Destroys the user's key and sends a refund based on the amount of time remaining.
   */
  function cancelAndRefund()
    external
  {
    _cancelAndRefund(msg.sender);
  }

  /**
   * @dev Cancels a key owned by a different user and sends the funds to the msg.sender.
   * @param _keyOwner this user's key will be canceled
   * @param _signature getCancelAndRefundApprovalHash signed by the _keyOwner
   */
  function cancelAndRefundFor(
    address _keyOwner,
    bytes calldata _signature
  ) external
  {
    require(
      ECDSA.recover(
        ECDSA.toEthSignedMessageHash(
          getCancelAndRefundApprovalHash(_keyOwner, msg.sender)
        ),
        _signature
      ) == _keyOwner, 'INVALID_SIGNATURE'
    );

    keyOwnerToNonce[_keyOwner]++;
    _cancelAndRefund(_keyOwner);
  }

  /**
   * @dev Increments the current nonce for the msg.sender.
   * This can be used to invalidate a previously signed message.
   */
  function incrementNonce(
  ) external
  {
    keyOwnerToNonce[msg.sender]++;
  }

  /**
   * Allow the owner to change the refund penalty.
   */
  function updateRefundPenalty(
    uint _refundPenaltyNumerator,
    uint _refundPenaltyDenominator
  )
    external
    onlyOwner
  {
    require(_refundPenaltyDenominator != 0, 'INVALID_RATE');

    emit RefundPenaltyChanged(
      refundPenaltyNumerator,
      refundPenaltyDenominator,
      _refundPenaltyNumerator,
      _refundPenaltyDenominator
    );
    refundPenaltyNumerator = _refundPenaltyNumerator;
    refundPenaltyDenominator = _refundPenaltyDenominator;
  }

  /**
   * @dev Determines how much of a refund a key owner would receive if they issued
   * a cancelAndRefund block.timestamp.
   * Note that due to the time required to mine a tx, the actual refund amount will be lower
   * than what the user reads from this call.
   */
  function getCancelAndRefundValueFor(
    address _owner
  )
    external view
    returns (uint refund)
  {
    return _getCancelAndRefundValue(_owner);
  }

  /**
   * @dev returns the hash to sign in order to allow another user to cancel on your behalf.
   */
  function getCancelAndRefundApprovalHash(
    address _keyOwner,
    address _txSender
  ) public view
    returns (bytes32 approvalHash)
  {
    return keccak256(
      abi.encodePacked(
        // Approval is specific to this Lock
        address(this),
        // Approval enables only one cancel call
        keyOwnerToNonce[_keyOwner],
        // Approval allows only one account to broadcast the tx
        _txSender
      )
    );
  }

  /**
   * @dev cancels the key for the given keyOwner and sends the refund to the msg.sender.
   */
  function _cancelAndRefund(
    address _keyOwner
  ) internal
  {
    Key storage key = _getKeyFor(_keyOwner);

    uint refund = _getCancelAndRefundValue(_keyOwner);

    emit CancelKey(key.tokenId, _keyOwner, msg.sender, refund);
    // expirationTimestamp is a proxy for hasKey, setting this to `block.timestamp` instead
    // of 0 so that we can still differentiate hasKey from hasValidKey.
    key.expirationTimestamp = block.timestamp;

    if (refund > 0) {
      // Security: doing this last to avoid re-entrancy concerns
      _transfer(msg.sender, refund);
    }
  }

  /**
   * @dev Determines how much of a refund a key owner would receive if they issued
   * a cancelAndRefund now.
   * @param _owner The owner of the key check the refund value for.
   */
  function _getCancelAndRefundValue(
    address _owner
  )
    private view
    hasValidKey(_owner)
    returns (uint refund)
  {
    Key storage key = _getKeyFor(_owner);
    // Math: safeSub is not required since `hasValidKey` confirms timeRemaining is positive
    uint timeRemaining = key.expirationTimestamp - block.timestamp;
    if(timeRemaining >= expirationDuration) {
      refund = keyPrice;
    } else {
      // Math: using safeMul in case keyPrice or timeRemaining is very large
      refund = keyPrice.mul(timeRemaining) / expirationDuration;
    }
    uint penalty = keyPrice.mul(refundPenaltyNumerator) / refundPenaltyDenominator;
    if (refund > penalty) {
      // Math: safeSub is not required since the if confirms this won't underflow
      refund -= penalty;
    } else {
      refund = 0;
    }
  }
}

// File: openzeppelin-solidity/contracts/utils/Address.sol

pragma solidity ^0.5.2;

/**
 * Utility library of inline functions on addresses
 */
library Address {
    /**
     * Returns whether the target address is a contract
     * @dev This function will return false if invoked during the constructor of a contract,
     * as the code is not actually created until after the constructor finishes.
     * @param account address of the account to check
     * @return whether the target address is a contract
     */
    function isContract(address account) internal view returns (bool) {
        uint256 size;
        // XXX Currently there is no better way to check if there is a contract in an address
        // than to check the size of the code at that address.
        // See https://ethereum.stackexchange.com/a/14016/36603
        // for more details about how this works.
        // TODO Check this again before the Serenity release, because all addresses will be
        // contracts then.
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

// File: contracts/mixins/MixinTransfer.sol

pragma solidity 0.5.7;









/**
 * @title Mixin for the transfer-related functions needed to meet the ERC721
 * standard.
 * @author Nick Furfaro
 * @dev `Mixins` are a design pattern seen in the 0x contracts.  It simply
 * separates logically groupings of code to ease readability.
 */

contract MixinTransfer is
  MixinFunds,
  MixinLockCore,
  MixinKeys,
  MixinApproval
{
  using SafeMath for uint;
  using Address for address;

  event TransferFeeChanged(
    uint oldTransferFeeNumerator,
    uint oldTransferFeeDenominator,
    uint transferFeeNumerator,
    uint transferFeeDenominator
  );

  // 0x150b7a02 == bytes4(keccak256('onERC721Received(address,address,uint256,bytes)'))
  bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

  // The fee relative to keyPrice to charge when transfering a Key to another account
  // (potentially on a 0x marketplace).
  // This is calculated as `keyPrice * transferFeeNumerator / transferFeeDenominator`.
  uint public transferFeeNumerator = 0;
  uint public transferFeeDenominator = 100;

  /**
   * This is payable because at some point we want to allow the LOCK to capture a fee on 2ndary
   * market transactions...
   */
  function transferFrom(
    address _from,
    address _recipient,
    uint _tokenId
  )
    public
    payable
    onlyIfAlive
    hasValidKey(_from)
    onlyKeyOwnerOrApproved(_tokenId)
  {
    require(_recipient != address(0), 'INVALID_ADDRESS');
    _chargeAtLeast(getTransferFee(_from));

    Key storage fromKey = _getKeyFor(_from);
    Key storage toKey = _getKeyFor(_recipient);

    uint previousExpiration = toKey.expirationTimestamp;

    if (toKey.tokenId == 0) {
      toKey.tokenId = fromKey.tokenId;
      _recordOwner(_recipient, toKey.tokenId);
    }

    if (previousExpiration <= block.timestamp) {
      // The recipient did not have a key, or had a key but it expired. The new expiration is the
      // sender's key expiration
      // an expired key is no longer a valid key, so the new tokenID is the sender's tokenID
      toKey.expirationTimestamp = fromKey.expirationTimestamp;
      toKey.tokenId = fromKey.tokenId;
      _recordOwner(_recipient, _tokenId);
    } else {
      // The recipient has a non expired key. We just add them the corresponding remaining time
      // SafeSub is not required since the if confirms `previousExpiration - block.timestamp` cannot underflow
      toKey.expirationTimestamp = fromKey
        .expirationTimestamp.add(previousExpiration - block.timestamp);
    }

    // Effectively expiring the key for the previous owner
    fromKey.expirationTimestamp = block.timestamp;

    // Set the tokenID to 0 for the previous owner to avoid duplicates
    fromKey.tokenId = 0;

    // Clear any previous approvals
    _clearApproval(_tokenId);

    // trigger event
    emit Transfer(
      _from,
      _recipient,
      _tokenId
    );
  }

  /**
  * @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,
    uint _tokenId
  )
    external
    payable
  {
    safeTransferFrom(_from, _to, _tokenId, '');
  }

  /**
  * @notice Transfers the ownership of an NFT from one address to another address.
  * When transfer is complete, this functions
  *  checks if `_to` is a smart contract (code size > 0). If so, it calls
  *  `onERC721Received` on `_to` and throws if the return value is not
  *  `bytes4(keccak256('onERC721Received(address,address,uint,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,
    uint _tokenId,
    bytes memory _data
  )
    public
    payable
    onlyIfAlive
    onlyKeyOwnerOrApproved(_tokenId)
    hasValidKey(ownerOf(_tokenId))
  {
    transferFrom(_from, _to, _tokenId);
    require(_checkOnERC721Received(_from, _to, _tokenId, _data), 'NON_COMPLIANT_ERC721_RECEIVER');

  }

  /**
   * Allow the Lock owner to change the transfer fee.
   */
  function updateTransferFee(
    uint _transferFeeNumerator,
    uint _transferFeeDenominator
  )
    external
    onlyOwner
  {
    require(_transferFeeDenominator != 0, 'INVALID_RATE');
    emit TransferFeeChanged(
      transferFeeNumerator,
      transferFeeDenominator,
      _transferFeeNumerator,
      _transferFeeDenominator
    );
    transferFeeNumerator = _transferFeeNumerator;
    transferFeeDenominator = _transferFeeDenominator;
  }

  /**
   * Determines how much of a fee a key owner would need to pay in order to
   * transfer the key to another account.  This is pro-rated so the fee goes down
   * overtime.
   * @param _owner The owner of the key check the transfer fee for.
   */
  function getTransferFee(
    address _owner
  )
    public view
    hasValidKey(_owner)
    returns (uint)
  {
    Key storage key = _getKeyFor(_owner);
    // Math: safeSub is not required since `hasValidKey` confirms timeRemaining is positive
    uint timeRemaining = key.expirationTimestamp - block.timestamp;
    uint fee;
    if(timeRemaining >= expirationDuration) {
      // Max the potential impact of this fee for keys with long durations remaining
      fee = keyPrice;
    } else {
      // Math: using safeMul in case keyPrice or timeRemaining is very large
      fee = keyPrice.mul(timeRemaining) / expirationDuration;
    }
    return fee.mul(transferFeeNumerator) / transferFeeDenominator;
  }

  /**
   * @dev Internal function to invoke `onERC721Received` on a target address
   * The call is not executed if the target address is not a contract
   * @param from address representing the previous owner of the given token ID
   * @param to target address that will receive the tokens
   * @param tokenId uint256 ID of the token to be transferred
   * @param _data bytes optional data to send along with the call
   * @return whether the call correctly returned the expected magic value
   */
  function _checkOnERC721Received(
    address from,
    address to,
    uint256 tokenId,
    bytes memory _data
  )
    internal
    returns (bool)
  {
    if (!to.isContract()) {
      return true;
    }
    bytes4 retval = IERC721Receiver(to).onERC721Received(
      msg.sender, from, tokenId, _data);
    return (retval == _ERC721_RECEIVED);
  }

}

// File: contracts/PublicLock.sol

pragma solidity 0.5.7;

















/**
 * @title The Lock contract
 * @author Julien Genestoux (unlock-protocol.com)
 * Eventually: implement ERC721.
 * @dev ERC165 allows our contract to be queried to determine whether it implements a given interface.
 * Every ERC-721 compliant contract must implement the ERC165 interface.
 * https://eips.ethereum.org/EIPS/eip-721
 */
contract PublicLock is
  IERC721,
  MixinNoFallback,
  ERC165,
  Ownable,
  ERC721Holder,
  MixinFunds,
  MixinDisableAndDestroy,
  MixinLockCore,
  MixinKeys,
  MixinLockMetadata,
  MixinGrantKeys,
  MixinPurchase,
  MixinApproval,
  MixinTransfer,
  MixinRefunds
{
  constructor(
    address _owner,
    uint _expirationDuration,
    address _tokenAddress,
    uint _keyPrice,
    uint _maxNumberOfKeys,
    string memory _lockName
  )
    public
    MixinFunds(_tokenAddress)
    MixinLockCore(_expirationDuration, _keyPrice, _maxNumberOfKeys)
    MixinLockMetadata(_lockName)
  {
    // registering the interface for erc721 with ERC165.sol using
    // the ID specified in the standard: https://eips.ethereum.org/EIPS/eip-721
    _registerInterface(0x80ac58cd);
    // We must manually initialize Ownable.sol
    Ownable.initialize(_owner);
  }

  // The version number of the current implementation on this network
  function publicLockVersion(
  ) external pure
    returns (uint16)
  {
    return 3;
  }
}

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":"","type":"uint256"}],"name":"owners","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","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":"_approved","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"refundPenaltyDenominator","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"refundPenaltyNumerator","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"unlockProtocol","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_page","type":"uint256"},{"name":"_pageSize","type":"uint256"}],"name":"getOwnersByPage","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"keyPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"expirationDuration","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"name":"","type":"bytes4"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_keyPrice","type":"uint256"}],"name":"updateKeyPrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"cancelAndRefund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_recipient","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_baseTokenURI","type":"string"}],"name":"setBaseTokenURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_refundPenaltyNumerator","type":"uint256"},{"name":"_refundPenaltyDenominator","type":"uint256"}],"name":"updateRefundPenalty","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"numberOfKeysSold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_transferFeeNumerator","type":"uint256"},{"name":"_transferFeeDenominator","type":"uint256"}],"name":"updateTransferFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isAlive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_a","type":"string"},{"name":"_b","type":"string"},{"name":"_c","type":"string"},{"name":"_d","type":"string"}],"name":"strConcat","outputs":[{"name":"_concatenatedString","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"keyOwnerToNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_i","type":"uint256"}],"name":"uint2Str","outputs":[{"name":"_uintAsString","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getCancelAndRefundValueFor","outputs":[{"name":"refund","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lockName","type":"string"}],"name":"updateLockName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"address2Str","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"incrementNonce","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":"_owner","type":"address"}],"name":"getHasValidKey","outputs":[{"name":"","type":"bool"}],"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":"_recipient","type":"address"},{"name":"_referrer","type":"address"}],"name":"purchaseForFrom","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"partialWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxNumberOfKeys","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lockSymbol","type":"string"}],"name":"updateLockSymbol","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipients","type":"address[]"},{"name":"_expirationTimestamps","type":"uint256[]"}],"name":"grantKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getTransferFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_keyOwner","type":"address"},{"name":"_txSender","type":"address"}],"name":"getCancelAndRefundApprovalHash","outputs":[{"name":"approvalHash","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"transferFeeNumerator","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"numberOfOwners","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":true,"inputs":[{"name":"_account","type":"address"}],"name":"getTokenIdFor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_owner","type":"address"}],"name":"isKeyOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_expirationTimestamp","type":"uint256"}],"name":"grantKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"tokenAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"expireKeyFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"destroyLock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"keyExpirationTimestampFor","outputs":[{"name":"timestamp","type":"uint256"}],"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":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_keyOwner","type":"address"},{"name":"_signature","type":"bytes"}],"name":"cancelAndRefundFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"disableLock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"publicLockVersion","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"transferFeeDenominator","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":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"}],"name":"purchaseFor","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_recipients","type":"address[]"},{"name":"_expirationTimestamp","type":"uint256"}],"name":"grantKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_owner","type":"address"},{"name":"_expirationDuration","type":"uint256"},{"name":"_tokenAddress","type":"address"},{"name":"_keyPrice","type":"uint256"},{"name":"_maxNumberOfKeys","type":"uint256"},{"name":"_lockName","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"tokenId","type":"uint256"},{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"sendTo","type":"address"},{"indexed":false,"name":"refund","type":"uint256"}],"name":"CancelKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldRefundPenaltyNumerator","type":"uint256"},{"indexed":false,"name":"oldRefundPenaltyDenominator","type":"uint256"},{"indexed":false,"name":"refundPenaltyNumerator","type":"uint256"},{"indexed":false,"name":"refundPenaltyDenominator","type":"uint256"}],"name":"RefundPenaltyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldTransferFeeNumerator","type":"uint256"},{"indexed":false,"name":"oldTransferFeeDenominator","type":"uint256"},{"indexed":false,"name":"transferFeeNumerator","type":"uint256"},{"indexed":false,"name":"transferFeeDenominator","type":"uint256"}],"name":"TransferFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"symbol","type":"string"}],"name":"NewLockSymbol","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"tokenId","type":"uint256"}],"name":"ExpireKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldKeyPrice","type":"uint256"},{"indexed":false,"name":"keyPrice","type":"uint256"}],"name":"PriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"balance","type":"uint256"},{"indexed":true,"name":"owner","type":"address"}],"name":"Destroy","type":"event"},{"anonymous":false,"inputs":[],"name":"Disable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":true,"name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_approved","type":"address"},{"indexed":true,"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"}]

6080604052600060755560646076556001607755600a6078553480156200002557600080fd5b50604051620049ab380380620049ab833981018060405260c08110156200004b57600080fd5b8151602083015160408401516060850151608086015160a087018051959794969395929491938201926401000000008111156200008757600080fd5b820160208101848111156200009b57600080fd5b8151640100000000811182820187101715620000b657600080fd5b50509291905050508085848487620000db6301ffc9a760e01b6200030260201b60201c565b6001600160a01b03811615806200015957506000816001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200012957600080fd5b505afa1580156200013e573d6000803e3d6000fd5b505050506040513d60208110156200015557600080fd5b5051115b620001c557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f494e56414c49445f544f4b454e00000000000000000000000000000000000000604482015290519081900360640190fd5b60678054600160a01b60ff02196001600160a01b039093166001600160a01b031990911617919091167401000000000000000000000000000000000000000017905563bbf81e008311156200027b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d41585f45585049524154494f4e5f3130305f59454152530000000000000000604482015290519081900360640190fd5b606880546001600160a01b03191633179055606992909255606a55606b558051620002ae90607090602084019062000488565b50620002c7635b5e139f60e01b6200030260201b60201c565b50620002e06380ac58cd60e01b6200030260201b60201c565b620002f6866200036f60201b62002ff81760201c565b5050505050506200052a565b7fffffffff0000000000000000000000000000000000000000000000000000000080821614156200033257600080fd5b7fffffffff00000000000000000000000000000000000000000000000000000000166000908152602081905260409020805460ff19166001179055565b600154610100900460ff1680620003915750620003916200048160201b60201c565b80620003a0575060015460ff16155b620003f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e8152602001806200497d602e913960400191505060405180910390fd5b6001805461010061ff00198216811760ff19168317909255603480546001600160a01b0319166001600160a01b0385811691909117918290556040519390920460ff16929116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3600180549115156101000261ff001990921691909117905550565b303b155b90565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620004cb57805160ff1916838001178555620004fb565b82800160010185558215620004fb579182015b82811115620004fb578251825591602001919060010190620004de565b50620005099291506200050d565b5090565b6200048591905b8082111562000509576000815560010162000514565b614443806200053a6000396000f3fe6080604052600436106103ce5760003560e01c806370a08231116101fd5780639b3f0b1711610118578063c1c98d03116100ab578063d42cfc411161007a578063d42cfc411461136e578063e985e9c514611383578063f2fde38b146113be578063f6e4641f146113f1578063f8faf94214611417576103ce565b8063c1c98d03146112d0578063c4d66de8146112e5578063c87b56dd14611318578063d1bbd49c14611342576103ce565b8063a843a4e7116100e7578063a843a4e714611139578063abdf82ce1461114e578063b88d4fde14611181578063b8968bb414611245576103ce565b80639b3f0b171461107d5780639d76ea58146110b65780639f98d3cb146110cb578063a22cb465146110fe576103ce565b80638d0361fc1161019057806393fd18441161015f57806393fd184414610fe757806395d89b4114610ffc578063970aaeb714611011578063994a8a7114611044576103ce565b80638d0361fc14610f6d5780638da5cb5b14610fa85780638f32d59b14610fbd5780638f98ce8f14610fd2576103ce565b806374b6c106116101cc57806374b6c10614610ddf578063782a4ade14610df45780637c7c425314610e6f57806383cb0fa914610f3a576103ce565b806370a0823114610d3f57806370efb77014610d72578063715018a614610da057806371d2ee6c14610db5576103ce565b806330176e13116102ed5780634bc5a135116102805780635fdb97e11161024f5780635fdb97e114610c9a578063627cdcb914610ccd5780636352211e14610ce25780636d8ea5b414610d0c576103ce565b80634bc5a13514610b8f5780634c7a12a014610bc257806352d6a8e414610bec578063550ef3a814610c1f576103ce565b80633d3359cb116102bc5780633d3359cb146108d45780634136aa351461090457806342842e0e1461091957806345e965cd1461094f576103ce565b806330176e13146107ff57806339f469861461087a5780633ba70e31146108aa5780633ccfd60b146108bf576103ce565b806310803b721161036557806318160ddd1161033457806318160ddd146107755780631f1ec0291461078a5780632009dc65146107b457806323b872dd146107c9576103ce565b806310803b72146105dd57806310e569731461065d57806311a4c03a14610672578063150b7a0214610687576103ce565b8063095ea7b3116103a1578063095ea7b31461055e5780630c79130f1461058c5780630ed3e2cc146105b35780630f15023b146105c8576103ce565b806301ffc9a71461041c578063025e7c271461046457806306fdde03146104aa578063081812fc14610534575b3480156103da57600080fd5b5060408051600160e51b62461bcd02815260206004820152600b6024820152600160a81b6a4e4f5f46414c4c4241434b02604482015290519081900360640190fd5b34801561042857600080fd5b506104506004803603602081101561043f57600080fd5b50356001600160e01b031916611492565b604080519115158252519081900360200190f35b34801561047057600080fd5b5061048e6004803603602081101561048757600080fd5b50356114b5565b604080516001600160a01b039092168252519081900360200190f35b3480156104b657600080fd5b506104bf6114dc565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104f95781810151838201526020016104e1565b50505050905090810190601f1680156105265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561054057600080fd5b5061048e6004803603602081101561055757600080fd5b5035611573565b61058a6004803603604081101561057457600080fd5b506001600160a01b038135169060200135611584565b005b34801561059857600080fd5b506105a1611723565b60408051918252519081900360200190f35b3480156105bf57600080fd5b506105a1611729565b3480156105d457600080fd5b5061048e61172f565b3480156105e957600080fd5b5061060d6004803603604081101561060057600080fd5b508035906020013561173e565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610649578181015183820152602001610631565b505050509050019250505060405180910390f35b34801561066957600080fd5b506105a1611863565b34801561067e57600080fd5b506105a1611869565b34801561069357600080fd5b50610758600480360360808110156106aa57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156106e457600080fd5b8201836020820111156106f657600080fd5b803590602001918460018302840111600160201b8311171561071757600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061186f945050505050565b604080516001600160e01b03199092168252519081900360200190f35b34801561078157600080fd5b506105a1611883565b34801561079657600080fd5b5061058a600480360360208110156107ad57600080fd5b5035611889565b3480156107c057600080fd5b5061058a611937565b61058a600480360360608110156107df57600080fd5b506001600160a01b03813581169160208101359091169060400135611942565b34801561080b57600080fd5b5061058a6004803603602081101561082257600080fd5b810190602081018135600160201b81111561083c57600080fd5b82018360208201111561084e57600080fd5b803590602001918460018302840111600160201b8311171561086f57600080fd5b509092509050611ba4565b34801561088657600080fd5b5061058a6004803603604081101561089d57600080fd5b5080359060200135611bc6565b3480156108b657600080fd5b506105a1611c76565b3480156108cb57600080fd5b5061058a611c7c565b3480156108e057600080fd5b5061058a600480360360408110156108f757600080fd5b5080359060200135611cf4565b34801561091057600080fd5b50610450611da4565b61058a6004803603606081101561092f57600080fd5b506001600160a01b03813581169160208101359091169060400135611db4565b34801561095b57600080fd5b506104bf6004803603608081101561097257600080fd5b810190602081018135600160201b81111561098c57600080fd5b82018360208201111561099e57600080fd5b803590602001918460018302840111600160201b831117156109bf57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610a1157600080fd5b820183602082011115610a2357600080fd5b803590602001918460018302840111600160201b83111715610a4457600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610a9657600080fd5b820183602082011115610aa857600080fd5b803590602001918460018302840111600160201b83111715610ac957600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610b1b57600080fd5b820183602082011115610b2d57600080fd5b803590602001918460018302840111600160201b83111715610b4e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611dcf945050505050565b348015610b9b57600080fd5b506105a160048036036020811015610bb257600080fd5b50356001600160a01b0316611f84565b348015610bce57600080fd5b506104bf60048036036020811015610be557600080fd5b5035611f96565b348015610bf857600080fd5b506105a160048036036020811015610c0f57600080fd5b50356001600160a01b031661205d565b348015610c2b57600080fd5b5061058a60048036036020811015610c4257600080fd5b810190602081018135600160201b811115610c5c57600080fd5b820183602082011115610c6e57600080fd5b803590602001918460018302840111600160201b83111715610c8f57600080fd5b509092509050612068565b348015610ca657600080fd5b506104bf60048036036020811015610cbd57600080fd5b50356001600160a01b0316612085565b348015610cd957600080fd5b5061058a61221d565b348015610cee57600080fd5b5061048e60048036036020811015610d0557600080fd5b5035612235565b348015610d1857600080fd5b5061045060048036036020811015610d2f57600080fd5b50356001600160a01b03166122b1565b348015610d4b57600080fd5b506105a160048036036020811015610d6257600080fd5b50356001600160a01b03166122d1565b61058a60048036036040811015610d8857600080fd5b506001600160a01b0381358116916020013516612346565b348015610dac57600080fd5b5061058a6123f7565b348015610dc157600080fd5b5061058a60048036036020811015610dd857600080fd5b5035612452565b348015610deb57600080fd5b506105a1612523565b348015610e0057600080fd5b5061058a60048036036020811015610e1757600080fd5b810190602081018135600160201b811115610e3157600080fd5b820183602082011115610e4357600080fd5b803590602001918460018302840111600160201b83111715610e6457600080fd5b509092509050612529565b348015610e7b57600080fd5b5061058a60048036036040811015610e9257600080fd5b810190602081018135600160201b811115610eac57600080fd5b820183602082011115610ebe57600080fd5b803590602001918460208302840111600160201b83111715610edf57600080fd5b919390929091602081019035600160201b811115610efc57600080fd5b820183602082011115610f0e57600080fd5b803590602001918460208302840111600160201b83111715610f2f57600080fd5b5090925090506125ab565b348015610f4657600080fd5b506105a160048036036020811015610f5d57600080fd5b50356001600160a01b031661260d565b348015610f7957600080fd5b506105a160048036036040811015610f9057600080fd5b506001600160a01b03813581169160200135166126d6565b348015610fb457600080fd5b5061048e61272d565b348015610fc957600080fd5b5061045061273c565b348015610fde57600080fd5b506105a161274d565b348015610ff357600080fd5b506105a1612753565b34801561100857600080fd5b506104bf612759565b34801561101d57600080fd5b506105a16004803603602081101561103457600080fd5b50356001600160a01b03166128e4565b34801561105057600080fd5b506104506004803603604081101561106757600080fd5b50803590602001356001600160a01b0316612954565b34801561108957600080fd5b5061058a600480360360408110156110a057600080fd5b506001600160a01b038135169060200135612975565b3480156110c257600080fd5b5061048e612990565b3480156110d757600080fd5b5061058a600480360360208110156110ee57600080fd5b50356001600160a01b031661299f565b34801561110a57600080fd5b5061058a6004803603604081101561112157600080fd5b506001600160a01b0381351690602001351515612a5c565b34801561114557600080fd5b5061058a612b73565b34801561115a57600080fd5b506105a16004803603602081101561117157600080fd5b50356001600160a01b0316612c32565b61058a6004803603608081101561119757600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156111d157600080fd5b8201836020820111156111e357600080fd5b803590602001918460018302840111600160201b8311171561120457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612cc4945050505050565b34801561125157600080fd5b5061058a6004803603604081101561126857600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561129257600080fd5b8201836020820111156112a457600080fd5b803590602001918460018302840111600160201b831117156112c557600080fd5b509092509050612e67565b3480156112dc57600080fd5b5061058a612f48565b3480156112f157600080fd5b5061058a6004803603602081101561130857600080fd5b50356001600160a01b0316612ff8565b34801561132457600080fd5b506104bf6004803603602081101561133b57600080fd5b50356130e7565b34801561134e57600080fd5b50611357613308565b6040805161ffff9092168252519081900360200190f35b34801561137a57600080fd5b506105a161330d565b34801561138f57600080fd5b50610450600480360360408110156113a657600080fd5b506001600160a01b0381358116916020013516613313565b3480156113ca57600080fd5b5061058a600480360360208110156113e157600080fd5b50356001600160a01b0316613341565b61058a6004803603602081101561140757600080fd5b50356001600160a01b031661335b565b34801561142357600080fd5b5061058a6004803603604081101561143a57600080fd5b810190602081018135600160201b81111561145457600080fd5b82018360208201111561146657600080fd5b803590602001918460208302840111600160201b8311171561148757600080fd5b9193509150356133bc565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b606f81815481106114c257fe5b6000918252602090912001546001600160a01b0316905081565b60708054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156115685780601f1061153d57610100808354040283529160200191611568565b820191906000526020600020905b81548152906001019060200180831161154b57829003601f168201915b505050505090505b90565b600061157e8261340b565b92915050565b606754600160a01b900460ff166115da5760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b806115e58133612954565b806115f557506115f58133613478565b8061160d575061160d61160782612235565b33613313565b6116615760408051600160e51b62461bcd02815260206004820152601a60248201527f4f4e4c595f4b45595f4f574e45525f4f525f415050524f564544000000000000604482015290519081900360640190fd5b336001600160a01b03841614156116b45760408051600160e51b62461bcd02815260206004820152600c6024820152600160a11b6b20a8282927ab22afa9a2a62302604482015290519081900360640190fd5b600082815260736020526040902080546001600160a01b0319166001600160a01b03851690811790915582906116e982612235565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b60785481565b60775481565b6068546001600160a01b031681565b606f546060906117985760408051600160e51b62461bcd02815260206004820152601360248201527f4e4f5f4f55545354414e44494e475f4b45595300000000000000000000000000604482015290519081900360640190fd5b606f5482908482029060009082840111156117bb5750606f5481810392506117c0565b508082015b6060836040519080825280602002602001820160405280156117ec578160200160208202803883390190505b5090506000835b8381101561185657606f818154811061180857fe5b9060005260206000200160009054906101000a90046001600160a01b031683838151811061183257fe5b6001600160a01b0390921660209283029190910190910152600191820191016117f3565b5090979650505050505050565b606a5481565b60695481565b600160e11b630a85bd01025b949350505050565b606c5490565b61189161273c565b61189a57600080fd5b606754600160a01b900460ff166118f05760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b606a805490829055604080518281526020810184905281517f8aa4fa52648a6d15edce8a179c792c86f3719d0cc3c572cf90f91948f0f2cb68929181900390910190a15050565b61194033613499565b565b606754600160a01b900460ff166119985760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b826119a2816122b1565b6119e95760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b816119f48133612954565b80611a045750611a048133613478565b80611a165750611a1661160782612235565b611a6a5760408051600160e51b62461bcd02815260206004820152601a60248201527f4f4e4c595f4b45595f4f574e45525f4f525f415050524f564544000000000000604482015290519081900360640190fd5b6001600160a01b038416611abd5760408051600160e51b62461bcd02815260206004820152600f6024820152600160881b6e494e56414c49445f4144445245535302604482015290519081900360640190fd5b611ace611ac98661260d565b61350e565b6000611ad986613740565b90506000611ae686613740565b6001810154815491925090611b05578254808355611b0590889061375a565b428111611b29576001808401549083015582548255611b24878761375a565b611b46565b6001830154611b409042830363ffffffff6137e116565b60018301555b42600184015560008355611b59866137fa565b85876001600160a01b0316896001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050505050565b611bac61273c565b611bb557600080fd5b611bc160728383614351565b505050565b611bce61273c565b611bd757600080fd5b80611c1e5760408051600160e51b62461bcd02815260206004820152600c6024820152600160a01b6b494e56414c49445f5241544502604482015290519081900360640190fd5b60775460785460408051928352602083019190915281810184905260608201839052517fa7d13855fe99b8c8b2780f36ff9e06133878b66a664a951b2375fe2296cc00089181900360800190a1607791909155607855565b606c5481565b611c8461273c565b611c8d57600080fd5b6000611c9830613835565b905060008111611ce85760408051600160e51b62461bcd0281526020600482015260106024820152600160801b6f4e4f545f454e4f5547485f46554e445302604482015290519081900360640190fd5b611cf1816138dc565b50565b611cfc61273c565b611d0557600080fd5b80611d4c5760408051600160e51b62461bcd02815260206004820152600c6024820152600160a01b6b494e56414c49445f5241544502604482015290519081900360640190fd5b60755460765460408051928352602083019190915281810184905260608201839052517ff0cc3b8bd450a20cce7720453e064b35cf490baa5d53c7c6ef8b2e1b02898a7d9181900360800190a1607591909155607655565b606754600160a01b900460ff1681565b611bc183838360405180602001604052806000815250612cc4565b606080859050606085905060608590506060859050606081518351855187510101016040519080825280601f01601f191660200182016040528015611e1b576020820181803883390190505b509050806000805b8751811015611e7457878181518110611e3857fe5b602001015160f81c60f81b838380600101945081518110611e5557fe5b60200101906001600160f81b031916908160001a905350600101611e23565b5060005b8651811015611ec957868181518110611e8d57fe5b602001015160f81c60f81b838380600101945081518110611eaa57fe5b60200101906001600160f81b031916908160001a905350600101611e78565b5060005b8551811015611f1e57858181518110611ee257fe5b602001015160f81c60f81b838380600101945081518110611eff57fe5b60200101906001600160f81b031916908160001a905350600101611ecd565b5060005b8451811015611f7357848181518110611f3757fe5b602001015160f81c60f81b838380600101945081518110611f5457fe5b60200101906001600160f81b031916908160001a905350600101611f22565b50909b9a5050505050505050505050565b60796020526000908152604090205481565b60608180611fc05750506040805180820190915260018152600160fc1b60030260208201526114b0565b8260005b8115611fd857600101600a82049150611fc4565b6060816040519080825280601f01601f191660200182016040528015612005576020820181803883390190505b50905060001982015b841561205357600a850660300160f81b8282806001900393508151811061203157fe5b60200101906001600160f81b031916908160001a905350600a8504945061200e565b5095945050505050565b600061157e82613926565b61207061273c565b61207957600080fd5b611bc160708383614351565b604080518082018252601081527f303132333435363738396162636465660000000000000000000000000000000060208201528151602a80825260608281019094526001600160a01b03851692918491602082018180388339019050509050600160fc1b600302816000815181106120f957fe5b60200101906001600160f81b031916908160001a905350600160fb1b600f028160018151811061212557fe5b60200101906001600160f81b031916908160001a90535060005b6014811015612214578260048583600c016020811061215a57fe5b1a60f81b6001600160f81b031916901c60f81c60ff168151811061217a57fe5b602001015160f81c60f81b82826002026002018151811061219757fe5b60200101906001600160f81b031916908160001a905350828482600c01602081106121be57fe5b1a60f81b600f60f81b1660f81c60ff16815181106121d857fe5b602001015160f81c60f81b8282600202600301815181106121f557fe5b60200101906001600160f81b031916908160001a90535060010161213f565b50949350505050565b33600090815260796020526040902080546001019055565b6000818152606e602052604081205482906001600160a01b03166122945760408051600160e51b62461bcd02815260206004820152600b6024820152600160a81b6a4e4f5f535543485f4b455902604482015290519081900360640190fd5b50506000908152606e60205260409020546001600160a01b031690565b6001600160a01b03166000908152606d6020526040902060010154421090565b60006001600160a01b0382166123265760408051600160e51b62461bcd02815260206004820152600f6024820152600160881b6e494e56414c49445f4144445245535302604482015290519081900360640190fd5b61232f826122b1565b61233a57600061233d565b60015b60ff1692915050565b606754600160a01b900460ff1661239c5760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b806123a6816122b1565b6123ed5760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b611bc18383613a0b565b6123ff61273c565b61240857600080fd5b6034546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603480546001600160a01b0319169055565b61245a61273c565b61246357600080fd5b600081116124bb5760408051600160e51b62461bcd02815260206004820152601160248201527f475245415445525f5448414e5f5a45524f000000000000000000000000000000604482015290519081900360640190fd5b60006124c630613835565b9050818110156125165760408051600160e51b62461bcd0281526020600482015260106024820152600160801b6f4e4f545f454e4f5547485f46554e445302604482015290519081900360640190fd5b61251f826138dc565b5050565b606b5481565b61253161273c565b61253a57600080fd5b61254660718383614351565b507f8868e22e84ebf32da89b2ebcb0ac642816304ea3863b257f240df9098719cb97828260405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a15050565b6125b361273c565b6125bc57600080fd5b60005b83811015612606576125fe8585838181106125d657fe5b905060200201356001600160a01b03168484848181106125f257fe5b90506020020135613cf1565b6001016125bf565b5050505050565b600081612619816122b1565b6126605760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b600061266b84613740565b905060004282600101540390506000606954821061268c5750606a546126ad565b606954606a546126a2908463ffffffff613e0716565b816126a957fe5b0490505b6076546075546126c490839063ffffffff613e0716565b816126cb57fe5b049695505050505050565b6001600160a01b0391821660009081526079602090815260409182902054825130606090811b8285015260348201929092529390941690931b60548301528051808303604801815260689092019052805191012090565b6034546001600160a01b031690565b6034546001600160a01b0316331490565b60755481565b606f5490565b6071546060906002600019610100600184161502019091160461285257606860009054906101000a90046001600160a01b03166001600160a01b03166335a750de6040518163ffffffff1660e01b815260040160006040518083038186803b1580156127c457600080fd5b505afa1580156127d8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561280157600080fd5b810190808051600160201b81111561281857600080fd5b8201602081018481111561282b57600080fd5b8151600160201b81118282018710171561284457600080fd5b509094506115709350505050565b6071805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156128d85780601f106128ad576101008083540402835291602001916128d8565b820191906000526020600020905b8154815290600101906020018083116128bb57829003601f168201915b50505050509050611570565b6000816128f0816122b1565b6129375760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b50506001600160a01b03166000908152606d602052604090205490565b6000918252606e6020526040909120546001600160a01b0391821691161490565b61297d61273c565b61298657600080fd5b61251f8282613cf1565b6067546001600160a01b031681565b6129a761273c565b6129b057600080fd5b806129ba816122b1565b612a015760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b6001600160a01b0382166000908152606d602090815260409182902042600182015580548351908152925190927f59f2fe866dd27a1c2d34115520888c3150365cbc931aab97fa88c4b9ab40b79592908290030190a1505050565b606754600160a01b900460ff16612ab25760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b6001600160a01b038216331415612b055760408051600160e51b62461bcd02815260206004820152600c6024820152600160a11b6b20a8282927ab22afa9a2a62302604482015290519081900360640190fd5b3360008181526074602090815260408083206001600160a01b03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b612b7b61273c565b612b8457600080fd5b606754600160a01b900460ff1615612be65760408051600160e51b62461bcd02815260206004820152600d60248201527f44495341424c455f464952535400000000000000000000000000000000000000604482015290519081900360640190fd5b6040805130318152905133917fa053f2a7eceda47dde76e5939c5adf7b771e665fc84c8ef6feffc290a1eb1feb919081900360200190a2612c2f33612c2a30613835565b613e2e565b33ff5b6001600160a01b0381166000908152606d60205260408120600101548290612ca45760408051600160e51b62461bcd02815260206004820152601360248201527f4841535f4e455645525f4f574e45445f4b455900000000000000000000000000604482015290519081900360640190fd5b50506001600160a01b03166000908152606d602052604090206001015490565b606754600160a01b900460ff16612d1a5760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b81612d258133612954565b80612d355750612d358133613478565b80612d475750612d4761160782612235565b612d9b5760408051600160e51b62461bcd02815260206004820152601a60248201527f4f4e4c595f4b45595f4f574e45525f4f525f415050524f564544000000000000604482015290519081900360640190fd5b612da483612235565b612dad816122b1565b612df45760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b612dff868686611942565b612e0b86868686614049565b612e5f5760408051600160e51b62461bcd02815260206004820152601d60248201527f4e4f4e5f434f4d504c49414e545f4552433732315f5245434549564552000000604482015290519081900360640190fd5b505050505050565b826001600160a01b0316612ec2612e86612e8186336126d6565b614182565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141d392505050565b6001600160a01b031614612f205760408051600160e51b62461bcd02815260206004820152601160248201527f494e56414c49445f5349474e4154555245000000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b038316600090815260796020526040902080546001019055611bc183613499565b612f5061273c565b612f5957600080fd5b606754600160a01b900460ff16612faf5760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b6040517f25a311358326fb18c62efc24bc28d3126acee8d2a67fd8b2145b757dc8bd1bc190600090a16067805474ff000000000000000000000000000000000000000019169055565b600154610100900460ff168061301157506130116142c1565b8061301f575060015460ff16155b61305d57604051600160e51b62461bcd02815260040180806020018281038252602e8152602001806143ea602e913960400191505060405180910390fd5b6001805461010061ff00198216811760ff19168317909255603480546001600160a01b0319166001600160a01b0385811691909117918290556040519390920460ff16929116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3600180549115156101000261ff001990921691909117905550565b6000818152606e602052604090205460609082906001600160a01b03166131495760408051600160e51b62461bcd02815260206004820152600b6024820152600160a81b6a4e4f5f535543485f4b455902604482015290519081900360640190fd5b6072546060906002600019610100600184161502019091160461324257606860009054906101000a90046001600160a01b03166001600160a01b0316637ff94bb26040518163ffffffff1660e01b815260040160006040518083038186803b1580156131b457600080fd5b505afa1580156131c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156131f157600080fd5b810190808051600160201b81111561320857600080fd5b8201602081018481111561321b57600080fd5b8151600160201b81118282018710171561323457600080fd5b509094506132d09350505050565b6072805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156132c85780601f1061329d576101008083540402835291602001916132c8565b820191906000526020600020905b8154815290600101906020018083116132ab57829003601f168201915b505050505090505b61187b816132dd30612085565b604051806040016040528060018152602001600160f81b602f0281525061330388611f96565b611dcf565b600390565b60765481565b6001600160a01b03918216600090815260746020908152604080832093909416825291909152205460ff1690565b61334961273c565b61335257600080fd5b611cf1816142c7565b606754600160a01b900460ff166133b15760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b611cf1816000613a0b565b6133c461273c565b6133cd57600080fd5b60005b82811015613405576133fd8484838181106133e757fe5b905060200201356001600160a01b031683613cf1565b6001016133d0565b50505050565b6000818152607360205260408120546001600160a01b03168061157e5760408051600160e51b62461bcd02815260206004820152600d60248201527f4e4f4e455f415050524f56454400000000000000000000000000000000000000604482015290519081900360640190fd5b600091825260736020526040909120546001600160a01b0391821691161490565b60006134a482613740565b905060006134b183613926565b825460408051838152905192935033926001600160a01b03871692917f0a7068a9989857441c039a14a42b67ed71dd1fcfe5a9b17cc87b252e47bce528919081900360200190a44260018301558015611bc157611bc13382613e2e565b8015611cf1576067546001600160a01b031661357757803410156135725760408051600160e51b62461bcd0281526020600482015260106024820152600160801b6f4e4f545f454e4f5547485f46554e445302604482015290519081900360640190fd5b611cf1565b60675460408051600160e01b6370a0823102815230600482015290516001600160a01b039092169160009183916370a0823191602480820192602092909190829003018186803b1580156135ca57600080fd5b505afa1580156135de573d6000803e3d6000fd5b505050506040513d60208110156135f457600080fd5b505160408051600160e01b6323b872dd0281523360048201523060248201526044810186905290519192506001600160a01b038416916323b872dd916064808201926020929091908290030181600087803b15801561365257600080fd5b505af1158015613666573d6000803e3d6000fd5b505050506040513d602081101561367c57600080fd5b505060408051600160e01b6370a08231028152306004820152905182916001600160a01b038516916370a0823191602480820192602092909190829003018186803b1580156136ca57600080fd5b505afa1580156136de573d6000803e3d6000fd5b505050506040513d60208110156136f457600080fd5b505111611bc15760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1514905394d1915497d1905253115102604482015290519081900360640190fd5b6001600160a01b03166000908152606d6020526040902090565b6000818152606e60205260409020546001600160a01b0383811691161461251f57606f8054600181019091557f39f2babe526038520877fc7c33d81accf578af4a06c5fa6b0d038cae36e127110180546001600160a01b0384166001600160a01b031991821681179092556000838152606e60205260409020805490911690911790555050565b6000828201838110156137f357600080fd5b9392505050565b6000818152607360205260409020546001600160a01b031615611cf157600090815260736020526040902080546001600160a01b0319169055565b6067546000906001600160a01b031661385957506001600160a01b038116316114b0565b60675460408051600160e01b6370a082310281526001600160a01b038581166004830152915191909216916370a08231916024808301926020929190829003018186803b1580156138a957600080fd5b505afa1580156138bd573d6000803e3d6000fd5b505050506040513d60208110156138d357600080fd5b505190506114b0565b6138ed6138e761272d565b82613e2e565b60408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b600081613932816122b1565b6139795760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b600061398484613740565b9050600042826001015403905060695481106139a457606a5493506139c5565b606954606a546139ba908363ffffffff613e0716565b816139c157fe5b0493505b60006078546139e1607754606a54613e0790919063ffffffff16565b816139e857fe5b049050808511156139fd578085039450613a02565b600094505b50505050919050565b606c54606b5411613a665760408051600160e51b62461bcd02815260206004820152600d60248201527f4c4f434b5f534f4c445f4f555400000000000000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b038216613ab95760408051600160e51b62461bcd02815260206004820152600f6024820152600160881b6e494e56414c49445f4144445245535302604482015290519081900360640190fd5b606a5460685460408051600160e01b630cb175e30281526001600160a01b03868116600483015260248201859052825160009586959094921692630cb175e3926044808301939192829003018186803b158015613b1557600080fd5b505afa158015613b29573d6000803e3d6000fd5b505050506040513d6040811015613b3f57600080fd5b50805160209091015190935091508080841115613b5e57506000613b63565b508281035b613b6c8161350e565b6000613b7787613740565b6001810154815491925090613bac57613b8f82614336565b613b9d88836000015461375a565b60695442016001830155613bc6565b606954613bc090829063ffffffff6137e116565b60018301555b8515613c3c5760685460408051600160e01b6336524663028152600481018990526024810188905290516001600160a01b039092169163365246639160448082019260009290919082900301818387803b158015613c2357600080fd5b505af1158015613c37573d6000803e3d6000fd5b505050505b60685460408051600160e01b63939d9f1f028152600481018690526001600160a01b038a811660248301529151919092169163939d9f1f91604480830192600092919082900301818387803b158015613c9457600080fd5b505af1158015613ca8573d6000803e3d6000fd5b5050606c546040519092506001600160a01b038b1691506000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050505050505050565b6001600160a01b038216613d445760408051600160e51b62461bcd02815260206004820152600f6024820152600160881b6e494e56414c49445f4144445245535302604482015290519081900360640190fd5b6000613d4f83613740565b905080600101548211613dac5760408051600160e51b62461bcd02815260206004820152601060248201527f414c52454144595f4f574e535f4b455900000000000000000000000000000000604482015290519081900360640190fd5b613db581614336565b613dc383826000015461375a565b6001810182905580546040516001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b600082613e165750600061157e565b82820282848281613e2357fe5b04146137f357600080fd5b801561251f576067546001600160a01b0316613e80576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015613e7a573d6000803e3d6000fd5b5061251f565b60675460408051600160e01b6370a082310281526001600160a01b0385811660048301529151919092169160009183916370a08231916024808301926020929190829003018186803b158015613ed557600080fd5b505afa158015613ee9573d6000803e3d6000fd5b505050506040513d6020811015613eff57600080fd5b505160408051600160e01b63a9059cbb0281526001600160a01b0387811660048301526024820187905291519293509084169163a9059cbb916044808201926020929091908290030181600087803b158015613f5a57600080fd5b505af1158015613f6e573d6000803e3d6000fd5b505050506040513d6020811015613f8457600080fd5b505060408051600160e01b6370a082310281526001600160a01b038681166004830152915183928516916370a08231916024808301926020929190829003018186803b158015613fd357600080fd5b505afa158015613fe7573d6000803e3d6000fd5b505050506040513d6020811015613ffd57600080fd5b5051116134055760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1514905394d1915497d1905253115102604482015290519081900360640190fd5b600061405d846001600160a01b031661434b565b6140695750600161187b565b604051600160e11b630a85bd0102815233600482018181526001600160a01b03888116602485015260448401879052608060648501908152865160848601528651600095928a169463150b7a029490938c938b938b939260a4019060208501908083838e5b838110156140e65781810151838201526020016140ce565b50505050905090810190601f1680156141135780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561413557600080fd5b505af1158015614149573d6000803e3d6000fd5b505050506040513d602081101561415f57600080fd5b50516001600160e01b031916600160e11b630a85bd010214915050949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b600081516041146141e65750600061157e565b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561422c576000935050505061157e565b8060ff16601b1415801561424457508060ff16601c14155b15614255576000935050505061157e565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa1580156142ac573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b303b1590565b6001600160a01b0381166142da57600080fd5b6034546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603480546001600160a01b0319166001600160a01b0392909216919091179055565b8054611cf157606c8054600101908190559055565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106143925782800160ff198235161785556143bf565b828001600101855582156143bf579182015b828111156143bf5782358255916020019190600101906143a4565b506143cb9291506143cf565b5090565b61157091905b808211156143cb57600081556001016143d556fe436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564a165627a7a7230582031474d01281aa90a56dde5554eed5c93cdafcfbf9c58bfb981584096593435520029436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a65640000000000000000000000003ca206264762caf81a8f0a843bbb850987b41e16000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d4d61792032387468204c6f636b00000000000000000000000000000000000000

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000003ca206264762caf81a8f0a843bbb850987b41e16000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d4d61792032387468204c6f636b00000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _owner (address): 0x3ca206264762caf81a8f0a843bbb850987b41e16
Arg [1] : _expirationDuration (uint256): 86400
Arg [2] : _tokenAddress (address): 0x0000000000000000000000000000000000000000
Arg [3] : _keyPrice (uint256): 0
Arg [4] : _maxNumberOfKeys (uint256): 115792089237316195423570985008687907853269984665640564039457584007913129639935
Arg [5] : _lockName (string): May 28th Lock

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000003ca206264762caf81a8f0a843bbb850987b41e16
Arg [1] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Arg [5] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [6] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [7] : 4d61792032387468204c6f636b00000000000000000000000000000000000000


Deployed ByteCode Sourcemap

66845:1056:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;44449:21:0;;;-1:-1:-1;;;;;44449:21:0;;;;;;;;;;;;-1:-1:-1;;;;;44449:21:0;;;;;;;;;;;;;;11588:135;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11588:135:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11588:135:0;-1:-1:-1;;;;;;11588:135:0;;:::i;:::-;;;;;;;;;;;;;;;;;;26768:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;26768:23:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;26768:23:0;;:::i;:::-;;;;-1:-1:-1;;;;;26768:23:0;;;;;;;;;;;;;;42243:94;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42243:94:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;42243:94:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34925:138;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34925:138:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;34925:138:0;;:::i;33955:311::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;33955:311:0;;;;;;;;:::i;:::-;;53428:41;;8:9:-1;5:2;;;30:1;27;20:12;5:2;53428:41:0;;;:::i;:::-;;;;;;;;;;;;;;;;53385:38;;8:9:-1;5:2;;;30:1;27;20:12;5:2;53385:38:0;;;:::i;22504:29::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;22504:29:0;;;:::i;29058:879::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;29058:879:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;29058:879:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;29058:879:0;;;;;;;;;;;;;;;;;22879:20;;8:9:-1;5:2;;;30:1;27;20:12;5:2;22879:20:0;;;:::i;22721:30::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;22721:30:0;;;:::i;13422:147::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;13422:147:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;13422:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;13422:147:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;13422:147:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;13422:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;13422:147:0;;-1:-1:-1;13422:147:0;;-1:-1:-1;;;;;13422:147:0:i;:::-;;;;-1:-1:-1;;;;;;13422:147:0;;;;;;;;;;;;;;25099:104;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25099:104:0;;;:::i;24762:213::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24762:213:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;24762:213:0;;:::i;54007:85::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54007:85:0;;;:::i;60759:1750::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;60759:1750:0;;;;;;;;;;;;;;;;;:::i;42996:134::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42996:134:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;42996:134:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;42996:134:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42996:134:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;42996:134:0;;-1:-1:-1;42996:134:0;-1:-1:-1;42996:134:0;:::i;55040:491::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;55040:491:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;55040:491:0;;;;;;;:::i;23067:28::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;23067:28:0;;;:::i;23860:268::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;23860:268:0;;;:::i;64065:463::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64065:463:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;64065:463:0;;;;;;;:::i;17668:19::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;17668:19:0;;;:::i;62862:174::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;62862:174:0;;;;;;;;;;;;;;;;;:::i;38910:820::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38910:820:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;38910:820:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;38910:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;38910:820:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;38910:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;38910:820:0;;;;;;;;-1:-1:-1;38910:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;38910:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;38910:820:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;38910:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;38910:820:0;;;;;;;;-1:-1:-1;38910:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;38910:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;38910:820:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;38910:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;38910:820:0;;;;;;;;-1:-1:-1;38910:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;38910:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;38910:820:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;38910:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;38910:820:0;;-1:-1:-1;38910:820:0;;-1:-1:-1;;;;;38910:820:0:i;53533:47::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;53533:47:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;53533:47:0;-1:-1:-1;;;;;53533:47:0;;:::i;39736:516::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;39736:516:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;39736:516:0;;:::i;55817:163::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;55817:163:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;55817:163:0;-1:-1:-1;;;;;55817:163:0;;:::i;42019:121::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42019:121:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;42019:121:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;42019:121:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42019:121:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;42019:121:0;;-1:-1:-1;42019:121:0;-1:-1:-1;42019:121:0;:::i;40258:457::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40258:457:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;40258:457:0;-1:-1:-1;;;;;40258:457:0;;:::i;54884:84::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54884:84:0;;;:::i;30923:150::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30923:150:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30923:150:0;;:::i;28359:171::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28359:171:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28359:171:0;-1:-1:-1;;;;;28359:171:0;;:::i;28094:197::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28094:197:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28094:197:0;-1:-1:-1;;;;;28094:197:0;;:::i;47434:209::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;47434:209:0;;;;;;;;;;:::i;9378:140::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9378:140:0;;;:::i;24308:342::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24308:342:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;24308:342:0;;:::i;22973:27::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;22973:27:0;;;:::i;42419:167::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42419:167:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;42419:167:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;42419:167:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42419:167:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;42419:167:0;;-1:-1:-1;42419:167:0;-1:-1:-1;42419:167:0;:::i;37738:257::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37738:257:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;37738:257:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;37738:257:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;37738:257:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;37738:257:0;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;37738:257:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;37738:257:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;37738:257:0;;-1:-1:-1;37738:257:0;-1:-1:-1;37738:257:0;:::i;64793:727::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64793:727:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;64793:727:0;-1:-1:-1;;;;;64793:727:0;;:::i;56093:456::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;56093:456:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;56093:456:0;;;;;;;;;;:::i;8665:79::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8665:79:0;;;:::i;9000:92::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9000:92:0;;;:::i;60531:36::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60531:36:0;;;:::i;30688:104::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30688:104:0;;;:::i;42691:215::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42691:215:0;;;:::i;28647:173::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28647:173:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28647:173:0;-1:-1:-1;;;;;28647:173:0;;:::i;30015:155::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30015:155:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30015:155:0;;;;;;-1:-1:-1;;;;;30015:155:0;;:::i;37020:163::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37020:163:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;37020:163:0;;;;;;;;:::i;14774:27::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;14774:27:0;;;:::i;27665:266::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;27665:266:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;27665:266:0;-1:-1:-1;;;;;27665:266:0;;:::i;34554:268::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34554:268:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;34554:268:0;;;;;;;;;;:::i;18338:501::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;18338:501:0;;;:::i;30328:200::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30328:200:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30328:200:0;-1:-1:-1;;;;;30328:200:0;;:::i;63608:382::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;63608:382:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;63608:382:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;63608:382:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;63608:382:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;63608:382:0;;-1:-1:-1;63608:382:0;;-1:-1:-1;;;;;63608:382:0:i;54337:401::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54337:401:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;54337:401:0;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;54337:401:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;54337:401:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;54337:401:0;;-1:-1:-1;54337:401:0;-1:-1:-1;54337:401:0;:::i;18076:121::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;18076:121:0;;;:::i;8452:145::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8452:145:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;8452:145:0;-1:-1:-1;;;;;8452:145:0;;:::i;43471:445::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43471:445:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43471:445:0;;:::i;67805:93::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;67805:93:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;60572:40;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60572:40:0;;;:::i;35380:173::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;35380:173:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;35380:173:0;;;;;;;;;;:::i;9695:109::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9695:109:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9695:109:0;-1:-1:-1;;;;;9695:109:0;;:::i;47070:154::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;47070:154:0;-1:-1:-1;;;;;47070:154:0;;:::i;37337:241::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37337:241:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;37337:241:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;37337:241:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;37337:241:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;37337:241:0;;-1:-1:-1;37337:241:0;-1:-1:-1;37337:241:0;;:::i;11588:135::-;-1:-1:-1;;;;;;11682:33:0;;11658:4;11682:33;;;;;;;;;;;;;11588:135;;;;:::o;26768:23::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;26768:23:0;;-1:-1:-1;26768:23:0;:::o;42243:94::-;42323:8;42316:15;;;;;;;;-1:-1:-1;;42316:15:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42291:13;;42316:15;;42323:8;;42316:15;;42323:8;42316:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42243:94;;:::o;34925:138::-;35009:7;35035:22;35048:8;35035:12;:22::i;:::-;35028:29;34925:138;-1:-1:-1;;34925:138:0:o;33955:311::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;34093:8;33568:32;33579:8;33589:10;33568;:32::i;:::-;:78;;;;33613:33;33625:8;33635:10;33613:11;:33::i;:::-;33568:138;;;;33659:47;33676:17;33684:8;33676:7;:17::i;:::-;33695:10;33659:16;:47::i;:::-;33552:192;;;;;-1:-1:-1;;;;;33552:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;34121:10;-1:-1:-1;;;;;34121:23:0;;;;34113:48;;;;;-1:-1:-1;;;;;34113:48:0;;;;;;;;;;;;-1:-1:-1;;;;;34113:48:0;;;;;;;;;;;;;;;34170:18;;;;:8;:18;;;;;:30;;-1:-1:-1;;;;;;34170:30:0;-1:-1:-1;;;;;34170:30:0;;;;;;;;:18;;34221:17;34170:18;34221:7;:17::i;:::-;-1:-1:-1;;;;;34212:48:0;;;;;;;;;;;17969:1;33955:311;;:::o;53428:41::-;;;;:::o;53385:38::-;;;;:::o;22504:29::-;;;-1:-1:-1;;;;;22504:29:0;;:::o;29058:879::-;29183:6;:13;29147:16;;29175:49;;;;;-1:-1:-1;;;;;29175:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;29362:6;:13;29247:9;;29282:16;;;;29231:13;;29337:22;;;:38;29333:202;;;-1:-1:-1;29403:6:0;:13;29436:27;;;;-1:-1:-1;29333:202:0;;;-1:-1:-1;29504:22:0;;;29333:202;29621:29;29667:8;29653:23;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;29653:23:0;-1:-1:-1;29621:55:0;-1:-1:-1;29683:14:0;29794:11;29780:124;29811:14;29807:1;:18;29780:124;;;29867:6;29874:1;29867:9;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;29867:9:0;29841:12;29854:9;29841:23;;;;;;;;-1:-1:-1;;;;;29841:35:0;;;:23;;;;;;;;;;;:35;29885:11;;;;;29827:3;29780:124;;;-1:-1:-1;29919:12:0;;29058:879;-1:-1:-1;;;;;;;29058:879:0:o;22879:20::-;;;;:::o;22721:30::-;;;;:::o;13422:147::-;-1:-1:-1;;;;;13422:147:0;;;;;;;:::o;25099:104::-;25181:16;;25099:104;:::o;24762:213::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;24887:8;;;24902:20;;;;24934:35;;;;;;;;;;;;;;;;;;;;;;;;;17969:1;24762:213;:::o;54007:85::-;54058:28;54075:10;54058:16;:28::i;:::-;54007:85::o;60759:1750::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;60910:5;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;60945:8;33568:32;33579:8;33589:10;33568;:32::i;:::-;:78;;;;33613:33;33625:8;33635:10;33613:11;:33::i;:::-;33568:138;;;;33659:47;33676:17;33684:8;33676:7;:17::i;33659:47::-;33552:192;;;;;-1:-1:-1;;;;;33552:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;60973:24:0;;60965:52;;;;;-1:-1:-1;;;;;60965:52:0;;;;;;;;;;;;-1:-1:-1;;;;;60965:52:0;;;;;;;;;;;;;;;61024:37;61039:21;61054:5;61039:14;:21::i;:::-;61024:14;:37::i;:::-;61070:19;61092:17;61103:5;61092:10;:17::i;:::-;61070:39;;61116:17;61136:22;61147:10;61136;:22::i;:::-;61193:25;;;;61231:13;;61116:42;;-1:-1:-1;61193:25:0;61227:120;;61276:15;;61260:31;;;61300:39;;61313:10;;61300:12;:39::i;:::-;61381:15;61359:18;:37;61355:764;;61662:27;;;;;61634:25;;;:55;61714:15;;61698:31;;61738:34;61751:10;61763:8;61738:12;:34::i;:::-;61355:764;;;62032:37;;;;:79;;62095:15;62074:36;;62032:79;:41;:79;:::i;:::-;62004:25;;;:107;61355:764;62217:15;62187:27;;;:45;62331:1;62313:19;;62378:24;62393:8;62378:14;:24::i;:::-;62488:8;62469:10;-1:-1:-1;;;;;62438:65:0;62455:5;-1:-1:-1;;;;;62438:65:0;;;;;;;;;;;33751:1;;;27197;17969;60759:1750;;;:::o;42996:134::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;43096:28;:12;43111:13;;43096:28;:::i;:::-;;42996:134;;:::o;55040:491::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;55193:30;55185:55;;;;;-1:-1:-1;;;;;55185:55:0;;;;;;;;;;;;-1:-1:-1;;;;;55185:55:0;;;;;;;;;;;;;;;55283:22;;55314:24;;55254:157;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55418:22;:48;;;;55473:24;:52;55040:491::o;23067:28::-;;;;:::o;23860:268::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;23919:12;23934:26;23954:4;23934:11;:26::i;:::-;23919:41;;23985:1;23975:7;:11;23967:40;;;;;-1:-1:-1;;;;;23967:40:0;;;;;;;;;;;;-1:-1:-1;;;;;23967:40:0;;;;;;;;;;;;;;;24104:18;24114:7;24104:9;:18::i;:::-;8898:1;23860:268::o;64065:463::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;64212:28;64204:53;;;;;-1:-1:-1;;;;;64204:53:0;;;;;;;;;;;;-1:-1:-1;;;;;64204:53:0;;;;;;;;;;;;;;;64296:20;;64325:22;;64269:147;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;64423:20;:44;;;;64474:22;:48;64065:463::o;17668:19::-;;;-1:-1:-1;;;17668:19:0;;;;;:::o;62862:174::-;62988:42;63005:5;63012:3;63017:8;62988:42;;;;;;;;;;;;:16;:42::i;38910:820::-;39057:33;39102:16;39127:2;39102:28;;39137:16;39162:2;39137:28;;39172:16;39197:2;39172:28;;39207:16;39232:2;39207:28;;39242:18;39313:3;:10;39300:3;:10;39287:3;:10;39274:3;:10;:23;:36;:49;39263:61;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;39263:61:0;87:34:-1;135:17;;-1:-1;39263:61:0;-1:-1:-1;39242:82:0;-1:-1:-1;39242:82:0;39370:6;;39404:69;39420:3;:10;39416:1;:14;39404:69;;;39459:3;39463:1;39459:6;;;;;;;;;;;;;;;;39446:5;39452:3;;;;;;39446:10;;;;;;;;;;;:19;-1:-1:-1;;;;;39446:19:0;;;;;;;;-1:-1:-1;39432:3:0;;39404:69;;;-1:-1:-1;39488:1:0;39479:69;39495:3;:10;39491:1;:14;39479:69;;;39534:3;39538:1;39534:6;;;;;;;;;;;;;;;;39521:5;39527:3;;;;;;39521:10;;;;;;;;;;;:19;-1:-1:-1;;;;;39521:19:0;;;;;;;;-1:-1:-1;39507:3:0;;39479:69;;;-1:-1:-1;39563:1:0;39554:69;39570:3;:10;39566:1;:14;39554:69;;;39609:3;39613:1;39609:6;;;;;;;;;;;;;;;;39596:5;39602:3;;;;;;39596:10;;;;;;;;;;;:19;-1:-1:-1;;;;;39596:19:0;;;;;;;;-1:-1:-1;39582:3:0;;39554:69;;;-1:-1:-1;39638:1:0;39629:69;39645:3;:10;39641:1;:14;39629:69;;;39684:3;39688:1;39684:6;;;;;;;;;;;;;;;;39671:5;39677:3;;;;;;39671:10;;;;;;;;;;;:19;-1:-1:-1;;;;;39671:19:0;;;;;;;;-1:-1:-1;39657:3:0;;39629:69;;;-1:-1:-1;39718:5:0;;38910:820;-1:-1:-1;;;;;;;;;;;38910:820:0:o;53533:47::-;;;;;;;;;;;;;:::o;39736:516::-;39804:27;39926:2;39939:7;39935:40;;-1:-1:-1;;39957:10:0;;;;;;;;;;;;-1:-1:-1;;;;;39957:10:0;;;;;;39935:40;39990:2;39981:6;40014:53;40021:6;;40014:53;;40038:5;;40057:2;40052:7;;;;40014:53;;;40073:17;40103:3;40093:14;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;40093:14:0;87:34:-1;135:17;;-1:-1;40093:14:0;-1:-1:-1;40073:34:0;-1:-1:-1;;;40123:7:0;;40137:84;40144:6;;40137:84;;40193:2;40189:1;:6;40184:2;:11;40173:24;;40161:4;40166:3;;;;;;;40161:9;;;;;;;;;;;:36;-1:-1:-1;;;;;40161:36:0;;;;;;;;-1:-1:-1;40211:2:0;40206:7;;;;40137:84;;;-1:-1:-1;40241:4:0;39736:516;-1:-1:-1;;;;;39736:516:0:o;55817:163::-;55912:11;55942:32;55967:6;55942:24;:32::i;42019:121::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;42114:20;:8;42125:9;;42114:20;:::i;40258:457::-;40405:42;;;;;;;;;;;;;;;;40473:13;;40483:2;40473:13;;;40334;40473;;;;;;-1:-1:-1;;;;;40383:14:0;;;40405:42;40334:13;;40473;;;21:6:-1;;104:10;40473:13:0;87:34:-1;135:17;;-1:-1;40473:13:0;40454:32;;-1:-1:-1;;;;;40493:3:0;40497:1;40493:6;;;;;;;;;;;:12;-1:-1:-1;;;;;40493:12:0;;;;;;;;;-1:-1:-1;;;;;40512:3:0;40516:1;40512:6;;;;;;;;;;;:12;-1:-1:-1;;;;;40512:12:0;;;;;;;;-1:-1:-1;40536:6:0;40531:154;40552:2;40548:1;:6;40531:154;;;40583:8;40615:1;40598:5;40604:1;40608:2;40604:6;40598:13;;;;;;;;;;-1:-1:-1;;;;;40598:18:0;;;;40592:25;;40583:35;;;;;;;;;;;;;;;;;;40570:3;40576:1;40578;40576:3;40574:1;:5;40570:10;;;;;;;;;;;:48;-1:-1:-1;;;;;40570:48:0;;;;;;;;;40640:8;40655:5;40661:1;40665:2;40661:6;40655:13;;;;;;;;;;40671:4;40655:20;;;40649:27;;40640:37;;;;;;;;;;;;;;;;;;40627:3;40633:1;40635;40633:3;40631:1;:5;40627:10;;;;;;;;;;;:50;-1:-1:-1;;;;;40627:50:0;;;;;;;;-1:-1:-1;40556:3:0;;40531:154;;;-1:-1:-1;40705:3:0;40258:457;-1:-1:-1;;;;40258:457:0:o;54884:84::-;54949:10;54933:27;;;;:15;:27;;;;;:29;;;;;;54884:84::o;30923:150::-;31017:7;27311:24;;;:14;:24;;;;;;30993:8;;-1:-1:-1;;;;;27311:24:0;27295:76;;;;;-1:-1:-1;;;;;27295:76:0;;;;;;;;;;;;-1:-1:-1;;;;;27295:76:0;;;;;;;;;;;;;;;-1:-1:-1;;31043:24:0;;;;:14;:24;;;;;;-1:-1:-1;;;;;31043:24:0;;30923:150::o;28359:171::-;-1:-1:-1;;;;;28468:18:0;28445:4;28468:18;;;:10;:18;;;;;:38;;;28509:15;-1:-1:-1;;28359:171:0:o;28094:197::-;28177:4;-1:-1:-1;;;;;28201:20:0;;28193:48;;;;;-1:-1:-1;;;;;28193:48:0;;;;;;;;;;;;-1:-1:-1;;;;;28193:48:0;;;;;;;;;;;;;;;28255:22;28270:6;28255:14;:22::i;:::-;:30;;28284:1;28255:30;;;28280:1;28255:30;28248:37;;;28094:197;-1:-1:-1;;28094:197:0:o;47434:209::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;47574:9;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;47602:35;47615:10;47627:9;47602:12;:35::i;9378:140::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;9461:6;;9440:40;;9477:1;;-1:-1:-1;;;;;9461:6:0;;9440:40;;9477:1;;9440:40;9491:6;:19;;-1:-1:-1;;;;;;9491:19:0;;;9378:140::o;24308:342::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;24404:1;24394:7;:11;24386:41;;;;;-1:-1:-1;;;;;24386:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;24434:12;24449:26;24469:4;24449:11;:26::i;:::-;24434:41;;24501:7;24490;:18;;24482:47;;;;;-1:-1:-1;;;;;24482:47:0;;;;;;;;;;;;-1:-1:-1;;;;;24482:47:0;;;;;;;;;;;;;;;24626:18;24636:7;24626:9;:18::i;:::-;8898:1;24308:342;:::o;22973:27::-;;;;:::o;42419:167::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;42518:24;:10;42531:11;;42518:24;:::i;:::-;;42554:26;42568:11;;42554:26;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;;74:27;42554:26:0;;137:4:-1;117:14;;;-1:-1;;113:30;157:16;;;42554:26:0;;;;-1:-1:-1;42554:26:0;;-1:-1:-1;;;;42554:26:0;42419:167;;:::o;37738:257::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;37881:6;37877:113;37893:22;;;37877:113;;;37931:51;37941:11;;37953:1;37941:14;;;;;;;;;;;;;-1:-1:-1;;;;;37941:14:0;37957:21;;37979:1;37957:24;;;;;;;;;;;;;37931:9;:51::i;:::-;37917:3;;37877:113;;;;37738:257;;;;:::o;64793:727::-;64899:4;64877:6;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;64915:15;64933:18;64944:6;64933:10;:18::i;:::-;64915:36;;65051:18;65098:15;65072:3;:23;;;:41;65051:62;;65120:8;65155:18;;65138:13;:35;65135:312;;-1:-1:-1;65276:8:0;;65135:312;;;65421:18;;65391:8;;:27;;65404:13;65391:27;:12;:27;:::i;:::-;:48;;;;;;65385:54;;65135:312;65492:22;;65468:20;;65460:29;;:3;;:29;:7;:29;:::i;:::-;:54;;;;;;;64793:727;-1:-1:-1;;;;;;64793:727:0:o;56093:456::-;-1:-1:-1;;;;;56416:26:0;;;56212:20;56416:26;;;:15;:26;;;;;;;;;;56269:267;;56350:4;56269:267;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;6:49;;56269:267:0;;;;;;56251:292;;;;;;56093:456::o;8665:79::-;8730:6;;-1:-1:-1;;;;;8730:6:0;8665:79;:::o;9000:92::-;9078:6;;-1:-1:-1;;;;;9078:6:0;9064:10;:20;;9000:92::o;60531:36::-;;;;:::o;30688:104::-;30773:6;:13;30688:104;:::o;42691:215::-;42775:10;42769:24;42741:13;;42769:24;-1:-1:-1;;42769:24:0;;;;;;;;;;;42766:135;;42816:14;;;;;;;;;-1:-1:-1;;;;;42816:14:0;-1:-1:-1;;;;;42816:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42816:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;42816:37:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;42816:37:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;42816:37:0;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;-1:-1;42816:37:0;;-1:-1:-1;42809:44:0;;-1:-1:-1;;;;42809:44:0;42766:135;42883:10;42876:17;;;;;;;;;;;;;-1:-1:-1;;42876:17:0;;;;;;;;;;;;;;;;;;;;;;;;;;;42883:10;42876:17;;42883:10;42876:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28647:173;28763:4;28739:8;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;28786:20:0;;;;;:10;:20;;;;;:28;;28647:173::o;30015:155::-;30107:4;30130:24;;;:14;:24;;;;;;;-1:-1:-1;;;;;30130:34:0;;;:24;;:34;;30015:155::o;37020:163::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;37134:43;37144:10;37156:20;37134:9;:43::i;14774:27::-;;;-1:-1:-1;;;;;14774:27:0;;:::o;27665:266::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;27757:6;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;27793:18:0;;27775:15;27793:18;;;:10;:18;;;;;;;;;27844:15;27818:23;;;:41;27913:11;;27903:22;;;;;;;27793:18;;27903:22;;;;;;;;;27197:1;8898;27665:266;:::o;34554:268::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;34669:17:0;;34676:10;34669:17;;34661:42;;;;;-1:-1:-1;;;;;34661:42:0;;;;;;;;;;;;-1:-1:-1;;;;;34661:42:0;;;;;;;;;;;;;;;34734:10;34710:35;;;;:23;:35;;;;;;;;-1:-1:-1;;;;;34710:40:0;;;;;;;;;;;;:52;;-1:-1:-1;;34710:52:0;;;;;;;;;;34774:42;;;;;;;34710:40;;34734:10;34774:42;;;;;;;;;;;34554:268;;:::o;18338:501::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;18408:7;;-1:-1:-1;;;18408:7:0;;;;:16;18400:42;;;;;-1:-1:-1;;;;;18400:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;18456;;;18472:4;18464:21;18456:42;;;;18487:10;;18456:42;;;;;;;;;;18577:49;18587:10;18599:26;18619:4;18599:11;:26::i;:::-;18577:9;:49::i;:::-;18646:10;18633:24;30328:200;-1:-1:-1;;;;;26938:18:0;;30451:14;26938:18;;;:10;:18;;;;;:38;;;30429:6;;26922:88;;;;;-1:-1:-1;;;;;26922:88:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;30484:18:0;;;;;:10;:18;;;;;:38;;;;30328:200::o;63608:382::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;63792:8;33568:32;33579:8;33589:10;33568;:32::i;:::-;:78;;;;33613:33;33625:8;33635:10;33613:11;:33::i;:::-;33568:138;;;;33659:47;33676:17;33684:8;33676:7;:17::i;33659:47::-;33552:192;;;;;-1:-1:-1;;;;;33552:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;63819:17;63827:8;63819:7;:17::i;:::-;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;63848:34;63861:5;63868:3;63873:8;63848:12;:34::i;:::-;63897:51;63920:5;63927:3;63932:8;63942:5;63897:22;:51::i;:::-;63889:93;;;;;-1:-1:-1;;;;;63889:93:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;33751:1;17969;63608:382;;;;:::o;54337:401::-;54624:9;-1:-1:-1;;;;;54461:172:0;:159;54485:105;54526:53;54557:9;54568:10;54526:30;:53::i;:::-;54485:28;:105::i;:::-;54601:10;;54461:159;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;54461:13:0;;-1:-1:-1;;;54461:159:0:i;:::-;-1:-1:-1;;;;;54461:172:0;;54445:216;;;;;-1:-1:-1;;;;;54445:216:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;54670:26:0;;;;;;:15;:26;;;;;:28;;;;;;54705:27;54686:9;54705:16;:27::i;18076:121::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;18160:9;;;;;;;18176:7;:15;;-1:-1:-1;;18176:15:0;;;18076:121::o;8452:145::-;6947:12;;;;;;;;:31;;;6963:15;:13;:15::i;:::-;6947:47;;;-1:-1:-1;6983:11:0;;;;6982:12;6947:47;6939:106;;;;-1:-1:-1;;;;;6939:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7077:12;;;;-1:-1:-1;;7096:19:0;;;;-1:-1:-1;;7122:18:0;;;;;;8518:6;:15;;-1:-1:-1;;;;;;8518:15:0;-1:-1:-1;;;;;8518:15:0;;;;;;;;;;;8549:40;;7077:12;;;;;;;8582:6;;;-1:-1:-1;;8549:40:0;;-1:-1:-1;;8549:40:0;7159:12;:30;;;;;;;-1:-1:-1;;7159:30:0;;;;;;;;;-1:-1:-1;8452:145:0:o;43471:445::-;27347:1;27311:24;;;:14;:24;;;;;;43570:13;;43547:8;;-1:-1:-1;;;;;27311:24:0;27295:76;;;;;-1:-1:-1;;;;;27295:76:0;;;;;;;;;;;;-1:-1:-1;;;;;27295:76:0;;;;;;;;;;;;;;;43628:12;43622:26;43595:17;;43622:26;-1:-1:-1;;43622:26:0;;;;;;;;;;;43619:138;;43670:14;;;;;;;;;-1:-1:-1;;;;;43670:14:0;-1:-1:-1;;;;;43670:36:0;;:38;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43670:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43670:38:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;43670:38:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;43670:38:0;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;-1:-1;43670:38:0;;-1:-1:-1;43619:138:0;;-1:-1:-1;;;;43619:138:0;;43737:12;43731:18;;;;;;;;;;;;;-1:-1:-1;;43731:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;43737:12;43731:18;;43737:12;43731:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43619:138;43772;43802:3;43814:38;43846:4;43814:23;:38::i;:::-;43772:138;;;;;;;;;;;;;-1:-1:-1;;;;;43772:138:0;;;43873:30;43894:8;43873:20;:30::i;:::-;43772:21;:138::i;67805:93::-;67891:1;67805:93;:::o;60572:40::-;;;;:::o;35380:173::-;-1:-1:-1;;;;;35505:31:0;;;35482:4;35505:31;;;:23;:31;;;;;;;;:42;;;;;;;;;;;;;;;35380:173::o;9695:109::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;9768:28;9787:8;9768:18;:28::i;47070:154::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;47182:36;47195:10;47215:1;47182:12;:36::i;37337:241::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;37468:6;37464:109;37480:22;;;37464:109;;;37518:47;37528:11;;37540:1;37528:14;;;;;;;;;;;;;-1:-1:-1;;;;;37528:14:0;37544:20;37518:9;:47::i;:::-;37504:3;;37464:109;;;;37337:241;;;:::o;35970:251::-;36055:7;36102:18;;;:8;:18;;;;;;-1:-1:-1;;;;;36102:18:0;36135:31;36127:57;;;;;-1:-1:-1;;;;;36127:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;35646:150;35740:4;35763:18;;;:8;:18;;;;;;;-1:-1:-1;;;;;35763:27:0;;;:18;;:27;;35646:150::o;56659:594::-;56733:15;56751:21;56762:9;56751:10;:21::i;:::-;56733:39;;56781:11;56795:35;56820:9;56795:24;:35::i;:::-;56854:11;;56844:53;;;;;;;;56781:49;;-1:-1:-1;56878:10:0;;-1:-1:-1;;;;;56844:53:0;;;56854:11;56844:53;;;;;;;;;;57096:15;57070:23;;;:41;57124:10;;57120:128;;57211:29;57221:10;57233:6;57211:9;:29::i;15335:684::-;15404:10;;15401:613;;15428:12;;-1:-1:-1;;;;;15428:12:0;15425:582;;15488:6;15475:9;:19;;15467:48;;;;;-1:-1:-1;;;;;15467:48:0;;;;;;;;;;;;-1:-1:-1;;;;;15467:48:0;;;;;;;;;;;;;;;15425:582;;;15564:12;;15609:30;;;-1:-1:-1;;;;;15609:30:0;;15633:4;15609:30;;;;;;-1:-1:-1;;;;;15564:12:0;;;;15542;;15564;;15609:15;;:30;;;;;;;;;;;;;;;15564:12;15609:30;;;5:2:-1;;;;30:1;27;20:12;5:2;15609:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;15609:30:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;15609:30:0;15650:53;;;-1:-1:-1;;;;;15650:53:0;;15669:10;15650:53;;;;15689:4;15650:53;;;;;;;;;;;;15609:30;;-1:-1:-1;;;;;;15650:18:0;;;;;:53;;;;;15609:30;;15650:53;;;;;;;;-1:-1:-1;15650:18:0;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;15650:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;15650:53:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;15931:30:0;;;-1:-1:-1;;;;;15931:30:0;;15955:4;15931:30;;;;;;15964:13;;-1:-1:-1;;;;;15931:15:0;;;;;:30;;;;;15650:53;;15931:30;;;;;;;;:15;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;15931:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;15931:30:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;15931:30:0;:46;15923:74;;;;;-1:-1:-1;;;;;15923:74:0;;;;;;;;;;;;-1:-1:-1;;;;;15923:74:0;;;;;;;;;;;;;;32038:128;-1:-1:-1;;;;;32142:18:0;32112:11;32142:18;;;:10;:18;;;;;;32038:128::o;31660:308::-;31751:24;;;;:14;:24;;;;;;-1:-1:-1;;;;;31751:34:0;;;:24;;:34;31747:216;;31847:6;27:10:-1;;39:1;23:18;;45:23;;;31847:19:0;;;;-1:-1:-1;;;;;31847:19:0;;-1:-1:-1;;;;;;31847:19:0;;;;;;;;-1:-1:-1;31922:24:0;;;:14;31847:19;31922:24;;;;:33;;;;;;;;;;31660:308;;:::o;46033:150::-;46091:7;46123:5;;;46147:6;;;;46139:15;;;;;;46174:1;46033:150;-1:-1:-1;;;46033:150:0:o;36371:162::-;36476:1;36446:18;;;:8;:18;;;;;;-1:-1:-1;;;;;36446:18:0;:32;36442:86;;36518:1;36489:18;;;:8;:18;;;;;:31;;-1:-1:-1;;;;;;36489:31:0;;;36371:162::o;16898:239::-;16994:12;;16975:4;;-1:-1:-1;;;;;16994:12:0;16991:141;;-1:-1:-1;;;;;;17038:16:0;;;17031:23;;16991:141;17091:12;;17084:40;;;-1:-1:-1;;;;;17084:40:0;;-1:-1:-1;;;;;17084:40:0;;;;;;;;;17091:12;;;;;17084:30;;:40;;;;;;;;;;;;;;17091:12;17084:40;;;5:2:-1;;;;30:1;27;20:12;5:2;17084:40:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;17084:40:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;17084:40:0;;-1:-1:-1;17077:47:0;;25384:140;25440:35;25450:15;:13;:15::i;:::-;25467:7;25440:9;:35::i;:::-;25487:31;;;;;;;;25498:10;;25487:31;;;;;;;;;;25384:140;:::o;57455:845::-;57572:11;57550:6;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;57595:15;57613:18;57624:6;57613:10;:18::i;:::-;57595:36;;57731:18;57778:15;57752:3;:23;;;:41;57731:62;;57820:18;;57803:13;:35;57800:232;;57858:8;;57849:17;;57800:232;;;58006:18;;57976:8;;:27;;57989:13;57976:27;:12;:27;:::i;:::-;:48;;;;;;57967:57;;57800:232;58038:12;58092:24;;58053:36;58066:22;;58053:8;;:12;;:36;;;;:::i;:::-;:63;;;;;;58038:78;;58136:7;58127:6;:16;58123:172;;;58247:7;58237:17;;;;58123:172;;;58286:1;58277:10;;58123:172;27197:1;;;57455:845;;;;:::o;48159:1778::-;23214:16;;23196:15;;:34;23188:60;;;;;-1:-1:-1;;;;;23188:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;48327:24:0;;48319:52;;;;;-1:-1:-1;;;;;48319:52:0;;;;;;;;;;;;-1:-1:-1;;;;;48319:52:0;;;;;;;;;;;;;;;48520:8;;48556:14;;:72;;;-1:-1:-1;;;;;48556:72:0;;-1:-1:-1;;;;;48556:72:0;;;;;;;;;;;;;;;48458:13;;;;48520:8;;48556:14;;;:42;;:72;;;;;;;;;;;;:14;:72;;;5:2:-1;;;;30:1;27;20:12;5:2;48556:72:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;48556:72:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;48556:72:0;;;;;;;;;-1:-1:-1;48556:72:0;-1:-1:-1;48651:16:0;48678:27;;;48674:239;;;-1:-1:-1;48727:1:0;48674:239;;;-1:-1:-1;48878:27:0;;;48674:239;48997:24;49012:8;48997:14;:24::i;:::-;49053:17;49073:22;49084:10;49073;:22::i;:::-;49128:25;;;;49164:13;;49053:42;;-1:-1:-1;49128:25:0;49160:475;;49193:24;49211:5;49193:17;:24::i;:::-;49226:39;49239:10;49251:5;:13;;;49226:12;:39::i;:::-;49453:18;;49435:15;:36;49407:25;;;:64;49160:475;;;49608:18;;49585:42;;:18;;:42;:22;:42;:::i;:::-;49557:25;;;:70;49160:475;49647:12;;49643:90;;49670:14;;:55;;;-1:-1:-1;;;;;49670:55:0;;;;;;;;;;;;;;;;-1:-1:-1;;;;;49670:14:0;;;;:37;;:55;;;;;:14;;:55;;;;;;;;:14;;:55;;;5:2:-1;;;;30:1;27;20:12;5:2;49670:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;49670:55:0;;;;49643:90;49741:14;;:53;;;-1:-1:-1;;;;;49741:53:0;;;;;;;;-1:-1:-1;;;;;49741:53:0;;;;;;;;;:14;;;;;:32;;:53;;;;;:14;;:53;;;;;;;:14;;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;49741:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;49908:16:0;;49830:101;;49908:16;;-1:-1:-1;;;;;;49830:101:0;;;-1:-1:-1;49855:1:0;;49830:101;;49855:1;;49830:101;23255:1;;;;;;48159:1778;;:::o;38050:560::-;-1:-1:-1;;;;;38157:24:0;;38149:52;;;;;-1:-1:-1;;;;;38149:52:0;;;;;;;;;;;;-1:-1:-1;;;;;38149:52:0;;;;;;;;;;;;;;;38210:17;38230:22;38241:10;38230;:22::i;:::-;38210:42;;38290:5;:25;;;38267:20;:48;38259:77;;;;;-1:-1:-1;;;;;38259:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;38345:24;38363:5;38345:17;:24::i;:::-;38376:39;38389:10;38401:5;:13;;;38376:12;:39::i;:::-;38422:25;;;:48;;;38584:13;;38506:98;;-1:-1:-1;;;;;38506:98:0;;;38584:13;;38506:98;;38584:13;;38506:98;38050:560;;;:::o;44786:433::-;44844:7;45088:6;45084:47;;-1:-1:-1;45118:1:0;45111:8;;45084:47;45155:5;;;45159:1;45155;:5;:1;45179:5;;;;;:10;45171:19;;;;;16177:645;16260:11;;16257:560;;16285:12;;-1:-1:-1;;;;;16285:12:0;16282:528;;16324:39;;-1:-1:-1;;;;;16324:30:0;;;:39;;;;;16355:7;;16324:39;;;;16355:7;16324:30;:39;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16324:39:0;16282:528;;;16412:12;;16457:20;;;-1:-1:-1;;;;;16457:20:0;;-1:-1:-1;;;;;16457:20:0;;;;;;;;;16412:12;;;;;16390;;16412;;16457:15;;:20;;;;;;;;;;;;;;16412:12;16457:20;;;5:2:-1;;;;30:1;27;20:12;5:2;16457:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16457:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;16457:20:0;16488:28;;;-1:-1:-1;;;;;16488:28:0;;-1:-1:-1;;;;;16488:28:0;;;;;;;;;;;;;;;16457:20;;-1:-1:-1;16488:14:0;;;;;;:28;;;;;16457:20;;16488:28;;;;;;;;-1:-1:-1;16488:14:0;:28;;;5:2:-1;;;;30:1;27;20:12;5:2;16488:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16488:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;16744:20:0;;;-1:-1:-1;;;;;16744:20:0;;-1:-1:-1;;;;;16744:20:0;;;;;;;;;16767:13;;16744:15;;;;;:20;;;;;16488:28;;16744:20;;;;;;;:15;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;16744:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16744:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;16744:20:0;:36;16736:64;;;;;-1:-1:-1;;;;;16736:64:0;;;;;;;;;;;;-1:-1:-1;;;;;16736:64:0;;;;;;;;;;;;;;66034:362;66182:4;66203:15;:2;-1:-1:-1;;;;;66203:13:0;;:15::i;:::-;66198:50;;-1:-1:-1;66236:4:0;66229:11;;66198:50;66270:78;;-1:-1:-1;;;;;66270:78:0;;66315:10;66270:78;;;;;;-1:-1:-1;;;;;66270:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;66254:13;;66270:36;;;;;;66315:10;;66327:4;;66333:7;;66342:5;;66270:78;;;;;;;;;;;66254:13;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;66270:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66270:78:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;66270:78:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;66270:78:0;-1:-1:-1;;;;;;66363:26:0;-1:-1:-1;;;;;66363:26:0;;-1:-1:-1;;66034:362:0;;;;;;:::o;52722:269::-;52924:58;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;52924:58:0;;;;;;;52914:69;;;;;;52722:269::o;50635:1930::-;50713:7;50776:9;:16;50796:2;50776:22;50772:74;;-1:-1:-1;50831:1:0;50815:19;;50772:74;51207:4;51192:20;;51186:27;51253:4;51238:20;;51232:27;51307:4;51292:20;;51286:27;50915:9;51278:36;52237:66;52224:79;;52220:129;;;52335:1;52320:17;;;;;;;52220:129;52365:1;:7;;52370:2;52365:7;;:18;;;;;52376:1;:7;;52381:2;52376:7;;52365:18;52361:68;;;52415:1;52400:17;;;;;;;52361:68;52533:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;52533:24:0;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;52533:24:0;;-1:-1:-1;;52533:24:0;;;50635:1930;-1:-1:-1;;;;;;;50635:1930:0:o;7284:476::-;7724:7;7712:20;7747:7;7284:476;:::o;9954:187::-;-1:-1:-1;;;;;10028:22:0;;10020:31;;;;;;10088:6;;10067:38;;-1:-1:-1;;;;;10067:38:0;;;;10088:6;;10067:38;;10088:6;;10067:38;10116:6;:17;;-1:-1:-1;;;;;;10116:17:0;-1:-1:-1;;;;;10116:17:0;;;;;;;;;;9954:187::o;31201:396::-;31279:12;;31275:317;;31440:16;:18;;;;;;;;31553:31;;31201:396::o;58845:627::-;59417:20;59456:8;;;58845:627::o;66845:1056::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;66845:1056:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66845:1056:0;;;-1:-1:-1;66845:1056:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;

Swarm Source

bzzr://31474d01281aa90a56dde5554eed5c93cdafcfbf9c58bfb98158409659343552
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.