ETH Price: $3,417.22 (-1.13%)
Gas: 6 Gwei

Token

Week In Ethereum - 3 year anniversary (KEY)
 

Overview

Max Total Supply

124 KEY

Holders

124

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
1 KEY
0xeDB341D148e683249e9D7D67a4c6843F3B1265A0
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x75fA3Aa7...543dAb465
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
PublicLock

Compiler Version
v0.5.9+commit.e560f70d

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2019-06-27
*/

// File: contracts/interfaces/IERC721.sol

pragma solidity 0.5.9;

/// @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 isTopLevelCall = !initializing;
    if (isTopLevelCall) {
      initializing = true;
      initialized = true;
    }

    _;

    if (isTopLevelCall) {
      initializing = false;
    }
  }

  /// @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.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * [EIP](https://eips.ethereum.org/EIPS/eip-165).
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others (`ERC165Checker`).
 *
 * For an implementation, see `ERC165`.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

pragma solidity ^0.5.0;


/**
 * @dev Implementation of the `IERC165` interface.
 *
 * Contracts may inherit from this and call `_registerInterface` to declare
 * their support of an interface.
 */
contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

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

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See `IERC165.supportsInterface`.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See `IERC165.supportsInterface`.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

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

pragma solidity ^0.5.0;

/**
 * @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.0;


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.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through `transferFrom`. This is
     * zero by default.
     *
     * This value changes when `approve` or `transferFrom` are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * > Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an `Approval` event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to `approve`. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// File: contracts/mixins/MixinFunds.sol

pragma solidity 0.5.9;



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

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

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

// File: contracts/mixins/MixinDisableAndDestroy.sol

pragma solidity 0.5.9;




/**
 * @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.9;


/**
 * @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.9;






/**
 * @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,
    address indexed beneficiary,
    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;

  // The account which will receive funds on withdrawal
  address public beneficiary;

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

  modifier onlyOwnerOrBeneficiary()
  {
    require(
      msg.sender == owner() || msg.sender == beneficiary,
      'ONLY_LOCK_OWNER_OR_BENEFICIARY'
    );
    _;
  }

  constructor(
    address _beneficiary,
    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.
    beneficiary = _beneficiary;
    expirationDuration = _expirationDuration;
    keyPrice = _keyPrice;
    maxNumberOfKeys = _maxNumberOfKeys;
  }

  /**
   * @dev Called by owner to withdraw all funds from the lock and send them to the `beneficiary`.
   * @param _amount specifies the max amount to withdraw, which may be reduced when
   * considering the available balance. Set to 0 or MAX_UINT to withdraw everything.
   *
   * TODO: consider allowing anybody to trigger this as long as it goes to owner anyway?
   *  -- however be wary of draining funds as it breaks the `cancelAndRefund` use case.
   */
  function withdraw(
    uint _amount
  ) external
    onlyOwnerOrBeneficiary
  {
    uint balance = getBalance(address(this));
    uint amount;
    if(_amount == 0 || _amount > balance)
    {
      require(balance > 0, 'NOT_ENOUGH_FUNDS');
      amount = balance;
    }
    else
    {
      amount = _amount;
    }

    emit Withdrawal(msg.sender, beneficiary, amount);
    // Security: re-entrancy not a risk as this is the last line of an external function
    _transfer(beneficiary, 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);
  }

  /**
   * A function which lets the owner of the lock update the beneficiary account,
   * which receives funds on withdrawal.
   */
  function updateBeneficiary(
    address _beneficiary
  ) external
    onlyOwnerOrBeneficiary
  {
    require(_beneficiary != address(0), 'INVALID_ADDRESS');
    beneficiary = _beneficiary;
  }

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

// File: contracts/mixins/MixinKeys.sol

pragma solidity 0.5.9;




/**
 * @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.9;





/**
 * @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.9;





/**
 * @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.9;

// 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.9;







/**
 * @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.9;


/**
 * @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.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot 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, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}

// File: contracts/mixins/MixinPurchase.sol

pragma solidity 0.5.9;







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

    // Assign the key
    Key storage toKey = _getKeyFor(_recipient);

    if (toKey.tokenId == 0) {
      // Assign a new tokenId (if a new owner or previously transfered)
      _assignNewTokenId(toKey);
      _recordOwner(_recipient, toKey.tokenId);
    }

    if (toKey.expirationTimestamp >= block.timestamp) {
      // This is an existing owner trying to extend their key
      toKey.expirationTimestamp = toKey.expirationTimestamp.add(expirationDuration);
    } else {
      // 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;
    }

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

    unlockProtocol.recordKeyPurchase(netPrice, _referrer);

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

    // We explicitly allow for greater amounts of ETH to allow 'donations'
    // Security: last line to minimize risk of re-entrancy
    _chargeAtLeast(netPrice);
  }
}

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

pragma solidity ^0.5.0;

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

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

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

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

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

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

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

// File: contracts/mixins/MixinRefunds.sol

pragma solidity 0.5.9;








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.0;

/**
 * @dev Collection of functions related to the address type,
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * This test is non-exhaustive, and there may be false-negatives: during the
     * execution of a contract's constructor, its address will be reported as
     * not containing a contract.
     *
     * > It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies in extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

// File: contracts/mixins/MixinTransfer.sol

pragma solidity 0.5.9;









/**
 * @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.9;

















/**
 * @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(_owner, _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 4;
  }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[{"name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","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":false,"inputs":[{"name":"_beneficiary","type":"address"}],"name":"updateBeneficiary","outputs":[],"payable":false,"stateMutability":"nonpayable","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":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_baseTokenURI","type":"string"}],"name":"setBaseTokenURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"beneficiary","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","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":"_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":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":true,"inputs":[{"name":"_account","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","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":true,"name":"beneficiary","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"}]

6080604052600060765560646077556001607855600a6079553480156200002557600080fd5b5060405162004af138038062004af1833981810160405260c08110156200004b57600080fd5b8151602083015160408401516060850151608086015160a087018051959794969395929491938201926401000000008111156200008757600080fd5b820160208101848111156200009b57600080fd5b8151640100000000811182820187101715620000b657600080fd5b50909350839250889150879050858588620000fa7f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b036200037316565b6001600160a01b03811615806200017857506000816001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200014857600080fd5b505afa1580156200015d573d6000803e3d6000fd5b505050506040513d60208110156200017457600080fd5b5051115b620001e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f494e56414c49445f544f4b454e00000000000000000000000000000000000000604482015290519081900360640190fd5b6067805460ff60a01b196001600160a01b039093166001600160a01b031990911617919091167401000000000000000000000000000000000000000017905563bbf81e008311156200029757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d41585f45585049524154494f4e5f3130305f59454152530000000000000000604482015290519081900360640190fd5b60688054336001600160a01b031991821617909155606d80549091166001600160a01b039590951694909417909355606991909155606a55606b558051620002e790607190602084019062000565565b506200031c7f5b5e139f000000000000000000000000000000000000000000000000000000006001600160e01b036200037316565b50620003517f80ac58cd000000000000000000000000000000000000000000000000000000006001600160e01b036200037316565b62000367866200044260201b620030891760201c565b50505050505062000607565b7fffffffff0000000000000000000000000000000000000000000000000000000080821614156200040557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015290519081900360640190fd5b7fffffffff00000000000000000000000000000000000000000000000000000000166000908152602081905260409020805460ff19166001179055565b600154610100900460ff1680620004675750620004676001600160e01b036200055e16565b8062000476575060015460ff16155b620004cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018062004ac3602e913960400191505060405180910390fd5b600154610100900460ff16158015620004f8576001805460ff1961ff00199091166101001716811790555b603480546001600160a01b0319166001600160a01b0384811691909117918290556040519116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a380156200055a576001805461ff00191690555b5050565b303b155b90565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620005a857805160ff1916838001178555620005d8565b82800160010185558215620005d8579182015b82811115620005d8578251825591602001919060010190620005bb565b50620005e6929150620005ea565b5090565b6200056291905b80821115620005e65760008155600101620005f1565b6144ac80620006176000396000f3fe6080604052600436106103e45760003560e01c80636d8ea5b4116102085780639d76ea5811610118578063c4d66de8116100ab578063e985e9c51161007a578063e985e9c5146113c6578063f2fde38b14611401578063f6e4641f14611434578063f8b2cb4f1461145a578063f8faf9421461148d576103e4565b8063c4d66de814611328578063c87b56dd1461135b578063d1bbd49c14611385578063d42cfc41146113b1576103e4565b8063abdf82ce116100e7578063abdf82ce14611191578063b88d4fde146111c4578063b8968bb414611288578063c1c98d0314611313576103e4565b80639d76ea58146110f95780639f98d3cb1461110e578063a22cb46514611141578063a843a4e71461117c576103e4565b80638d0361fc1161019b57806393fd18441161016a57806393fd18441461102a57806395d89b411461103f578063970aaeb714611054578063994a8a71146110875780639b3f0b17146110c0576103e4565b80638d0361fc14610fb05780638da5cb5b14610feb5780638f32d59b146110005780638f98ce8f14611015576103e4565b806374b6c106116101d757806374b6c10614610e22578063782a4ade14610e375780637c7c425314610eb257806383cb0fa914610f7d576103e4565b80636d8ea5b414610d7957806370a0823114610dac57806370efb77014610ddf578063715018a614610e0d576103e4565b806323b872dd1161030357806342842e0e1161029657806352d6a8e41161026557806352d6a8e414610c59578063550ef3a814610c8c5780635fdb97e114610d07578063627cdcb914610d3a5780636352211e14610d4f576103e4565b806342842e0e1461098657806345e965cd146109bc5780634bc5a13514610bfc5780634c7a12a014610c2f576103e4565b806339f46986116102d257806339f46986146108fc5780633ba70e311461092c5780633d3359cb146109415780634136aa3514610971576103e4565b806323b872dd1461080c5780632e1a7d4d1461084257806330176e131461086c57806338af3eed146108e7576103e4565b80630f15023b1161037b578063150b7a021161034a578063150b7a02146106ca57806318160ddd146107b85780631f1ec029146107cd5780632009dc65146107f7576103e4565b80630f15023b1461060b57806310803b721461062057806310e56973146106a057806311a4c03a146106b5576103e4565b8063095ea7b3116103b7578063095ea7b31461056e5780630aaffd2a1461059c5780630c79130f146105cf5780630ed3e2cc146105f6576103e4565b806301ffc9a71461042c578063025e7c271461047457806306fdde03146104ba578063081812fc14610544575b3480156103f057600080fd5b506040805162461bcd60e51b815260206004820152600b60248201526a4e4f5f46414c4c4241434b60a81b604482015290519081900360640190fd5b34801561043857600080fd5b506104606004803603602081101561044f57600080fd5b50356001600160e01b031916611508565b604080519115158252519081900360200190f35b34801561048057600080fd5b5061049e6004803603602081101561049757600080fd5b503561152b565b604080516001600160a01b039092168252519081900360200190f35b3480156104c657600080fd5b506104cf611552565b6040805160208082528351818301528351919283929083019185019080838360005b838110156105095781810151838201526020016104f1565b50505050905090810190601f1680156105365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561055057600080fd5b5061049e6004803603602081101561056757600080fd5b50356115e9565b61059a6004803603604081101561058457600080fd5b506001600160a01b0381351690602001356115fa565b005b3480156105a857600080fd5b5061059a600480360360208110156105bf57600080fd5b50356001600160a01b0316611787565b3480156105db57600080fd5b506105e4611878565b60408051918252519081900360200190f35b34801561060257600080fd5b506105e461187e565b34801561061757600080fd5b5061049e611884565b34801561062c57600080fd5b506106506004803603604081101561064357600080fd5b5080359060200135611893565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561068c578181015183820152602001610674565b505050509050019250505060405180910390f35b3480156106ac57600080fd5b506105e46119ab565b3480156106c157600080fd5b506105e46119b1565b3480156106d657600080fd5b5061079b600480360360808110156106ed57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561072757600080fd5b82018360208201111561073957600080fd5b803590602001918460018302840111600160201b8311171561075a57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506119b7945050505050565b604080516001600160e01b03199092168252519081900360200190f35b3480156107c457600080fd5b506105e46119c8565b3480156107d957600080fd5b5061059a600480360360208110156107f057600080fd5b50356119ce565b34801561080357600080fd5b5061059a611a76565b61059a6004803603606081101561082257600080fd5b506001600160a01b03813581169160208101359091169060400135611a81565b34801561084e57600080fd5b5061059a6004803603602081101561086557600080fd5b5035611ccb565b34801561087857600080fd5b5061059a6004803603602081101561088f57600080fd5b810190602081018135600160201b8111156108a957600080fd5b8201836020820111156108bb57600080fd5b803590602001918460018302840111600160201b831117156108dc57600080fd5b509092509050611e1f565b3480156108f357600080fd5b5061049e611e3c565b34801561090857600080fd5b5061059a6004803603604081101561091f57600080fd5b5080359060200135611e4b565b34801561093857600080fd5b506105e4611ef5565b34801561094d57600080fd5b5061059a6004803603604081101561096457600080fd5b5080359060200135611efb565b34801561097d57600080fd5b50610460611fa5565b61059a6004803603606081101561099c57600080fd5b506001600160a01b03813581169160208101359091169060400135611fb5565b3480156109c857600080fd5b506104cf600480360360808110156109df57600080fd5b810190602081018135600160201b8111156109f957600080fd5b820183602082011115610a0b57600080fd5b803590602001918460018302840111600160201b83111715610a2c57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610a7e57600080fd5b820183602082011115610a9057600080fd5b803590602001918460018302840111600160201b83111715610ab157600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610b0357600080fd5b820183602082011115610b1557600080fd5b803590602001918460018302840111600160201b83111715610b3657600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610b8857600080fd5b820183602082011115610b9a57600080fd5b803590602001918460018302840111600160201b83111715610bbb57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611fd0945050505050565b348015610c0857600080fd5b506105e460048036036020811015610c1f57600080fd5b50356001600160a01b0316612185565b348015610c3b57600080fd5b506104cf60048036036020811015610c5257600080fd5b5035612197565b348015610c6557600080fd5b506105e460048036036020811015610c7c57600080fd5b50356001600160a01b031661225b565b348015610c9857600080fd5b5061059a60048036036020811015610caf57600080fd5b810190602081018135600160201b811115610cc957600080fd5b820183602082011115610cdb57600080fd5b803590602001918460018302840111600160201b83111715610cfc57600080fd5b509092509050612266565b348015610d1357600080fd5b506104cf60048036036020811015610d2a57600080fd5b50356001600160a01b0316612283565b348015610d4657600080fd5b5061059a6123ff565b348015610d5b57600080fd5b5061049e60048036036020811015610d7257600080fd5b5035612417565b348015610d8557600080fd5b5061046060048036036020811015610d9c57600080fd5b50356001600160a01b031661248d565b348015610db857600080fd5b506105e460048036036020811015610dcf57600080fd5b50356001600160a01b03166124ad565b61059a60048036036040811015610df557600080fd5b506001600160a01b038135811691602001351661251c565b348015610e1957600080fd5b5061059a6125c1565b348015610e2e57600080fd5b506105e461261c565b348015610e4357600080fd5b5061059a60048036036020811015610e5a57600080fd5b810190602081018135600160201b811115610e7457600080fd5b820183602082011115610e8657600080fd5b803590602001918460018302840111600160201b83111715610ea757600080fd5b509092509050612622565b348015610ebe57600080fd5b5061059a60048036036040811015610ed557600080fd5b810190602081018135600160201b811115610eef57600080fd5b820183602082011115610f0157600080fd5b803590602001918460208302840111600160201b83111715610f2257600080fd5b919390929091602081019035600160201b811115610f3f57600080fd5b820183602082011115610f5157600080fd5b803590602001918460208302840111600160201b83111715610f7257600080fd5b5090925090506126a4565b348015610f8957600080fd5b506105e460048036036020811015610fa057600080fd5b50356001600160a01b0316612706565b348015610fbc57600080fd5b506105e460048036036040811015610fd357600080fd5b506001600160a01b03813581169160200135166127c9565b348015610ff757600080fd5b5061049e61282d565b34801561100c57600080fd5b5061046061283c565b34801561102157600080fd5b506105e461284d565b34801561103657600080fd5b506105e4612853565b34801561104b57600080fd5b506104cf612859565b34801561106057600080fd5b506105e46004803603602081101561107757600080fd5b50356001600160a01b03166129e4565b34801561109357600080fd5b50610460600480360360408110156110aa57600080fd5b50803590602001356001600160a01b0316612a4e565b3480156110cc57600080fd5b5061059a600480360360408110156110e357600080fd5b506001600160a01b038135169060200135612a6f565b34801561110557600080fd5b5061049e612a8e565b34801561111a57600080fd5b5061059a6004803603602081101561113157600080fd5b50356001600160a01b0316612a9d565b34801561114d57600080fd5b5061059a6004803603604081101561116457600080fd5b506001600160a01b0381351690602001351515612b54565b34801561118857600080fd5b5061059a612c5f565b34801561119d57600080fd5b506105e4600480360360208110156111b457600080fd5b50356001600160a01b0316612d0b565b61059a600480360360808110156111da57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561121457600080fd5b82018360208201111561122657600080fd5b803590602001918460018302840111600160201b8311171561124757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612d90945050505050565b34801561129457600080fd5b5061059a600480360360408110156112ab57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156112d557600080fd5b8201836020820111156112e757600080fd5b803590602001918460018302840111600160201b8311171561130857600080fd5b509092509050612f1e565b34801561131f57600080fd5b5061059a612ff0565b34801561133457600080fd5b5061059a6004803603602081101561134b57600080fd5b50356001600160a01b0316613089565b34801561136757600080fd5b506104cf6004803603602081101561137e57600080fd5b5035613179565b34801561139157600080fd5b5061139a613391565b6040805161ffff9092168252519081900360200190f35b3480156113bd57600080fd5b506105e4613396565b3480156113d257600080fd5b50610460600480360360408110156113e957600080fd5b506001600160a01b038135811691602001351661339c565b34801561140d57600080fd5b5061059a6004803603602081101561142457600080fd5b50356001600160a01b03166133ca565b61059a6004803603602081101561144a57600080fd5b50356001600160a01b03166133e7565b34801561146657600080fd5b506105e46004803603602081101561147d57600080fd5b50356001600160a01b0316613442565b34801561149957600080fd5b5061059a600480360360408110156114b057600080fd5b810190602081018135600160201b8111156114ca57600080fd5b8201836020820111156114dc57600080fd5b803590602001918460208302840111600160201b831117156114fd57600080fd5b9193509150356134e6565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b6070818154811061153857fe5b6000918252602090912001546001600160a01b0316905081565b60718054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156115de5780601f106115b3576101008083540402835291602001916115de565b820191906000526020600020905b8154815290600101906020018083116115c157829003601f168201915b505050505090505b90565b60006115f482613535565b92915050565b606754600160a01b900460ff1661164a576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b806116558133612a4e565b806116655750611665813361358f565b8061167d575061167d61167782612417565b3361339c565b6116cb576040805162461bcd60e51b815260206004820152601a60248201527913d3931657d2d15657d3d5d3915497d3d497d054141493d5915160321b604482015290519081900360640190fd5b336001600160a01b0384161415611718576040805162461bcd60e51b815260206004820152600c60248201526b20a8282927ab22afa9a2a62360a11b604482015290519081900360640190fd5b600082815260746020526040902080546001600160a01b0319166001600160a01b038516908117909155829061174d82612417565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b61178f61282d565b6001600160a01b0316336001600160a01b031614806117b85750606d546001600160a01b031633145b611809576040805162461bcd60e51b815260206004820152601e60248201527f4f4e4c595f4c4f434b5f4f574e45525f4f525f42454e45464943494152590000604482015290519081900360640190fd5b6001600160a01b038116611856576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b606d80546001600160a01b0319166001600160a01b0392909216919091179055565b60795481565b60785481565b6068546001600160a01b031681565b6070546060906118e0576040805162461bcd60e51b81526020600482015260136024820152724e4f5f4f55545354414e44494e475f4b45595360681b604482015290519081900360640190fd5b607054829084820290600090828401111561190357506070548181039250611908565b508082015b606083604051908082528060200260200182016040528015611934578160200160208202803883390190505b5090506000835b8381101561199e576070818154811061195057fe5b9060005260206000200160009054906101000a90046001600160a01b031683838151811061197a57fe5b6001600160a01b03909216602092830291909101909101526001918201910161193b565b5090979650505050505050565b606a5481565b60695481565b630a85bd0160e11b5b949350505050565b606c5490565b6119d661283c565b6119df57600080fd5b606754600160a01b900460ff16611a2f576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b606a805490829055604080518281526020810184905281517f8aa4fa52648a6d15edce8a179c792c86f3719d0cc3c572cf90f91948f0f2cb68929181900390910190a15050565b611a7f336135b0565b565b606754600160a01b900460ff16611ad1576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b82611adb8161248d565b611b1c576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b81611b278133612a4e565b80611b375750611b37813361358f565b80611b495750611b4961167782612417565b611b97576040805162461bcd60e51b815260206004820152601a60248201527913d3931657d2d15657d3d5d3915497d3d497d054141493d5915160321b604482015290519081900360640190fd5b6001600160a01b038416611be4576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b611bf5611bf086612706565b613625565b6000611c0086613842565b90506000611c0d86613842565b6001810154815491925090611c2c578254808355611c2c90889061385c565b428111611c50576001808401549083015582548255611c4b878761385c565b611c6d565b6001830154611c679042830363ffffffff6138e316565b60018301555b42600184015560008355611c8086613944565b85876001600160a01b0316896001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050505050565b611cd361282d565b6001600160a01b0316336001600160a01b03161480611cfc5750606d546001600160a01b031633145b611d4d576040805162461bcd60e51b815260206004820152601e60248201527f4f4e4c595f4c4f434b5f4f574e45525f4f525f42454e45464943494152590000604482015290519081900360640190fd5b6000611d5830613442565b90506000821580611d6857508183115b15611dbc5760008211611db5576040805162461bcd60e51b815260206004820152601060248201526f4e4f545f454e4f5547485f46554e445360801b604482015290519081900360640190fd5b5080611dbf565b50815b606d546040805183815290516001600160a01b039092169133917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398919081900360200190a3606d54611e1a906001600160a01b03168261397f565b505050565b611e2761283c565b611e3057600080fd5b611e1a60738383614390565b606d546001600160a01b031681565b611e5361283c565b611e5c57600080fd5b80611e9d576040805162461bcd60e51b815260206004820152600c60248201526b494e56414c49445f5241544560a01b604482015290519081900360640190fd5b60785460795460408051928352602083019190915281810184905260608201839052517fa7d13855fe99b8c8b2780f36ff9e06133878b66a664a951b2375fe2296cc00089181900360800190a1607891909155607955565b606c5481565b611f0361283c565b611f0c57600080fd5b80611f4d576040805162461bcd60e51b815260206004820152600c60248201526b494e56414c49445f5241544560a01b604482015290519081900360640190fd5b60765460775460408051928352602083019190915281810184905260608201839052517ff0cc3b8bd450a20cce7720453e064b35cf490baa5d53c7c6ef8b2e1b02898a7d9181900360800190a1607691909155607755565b606754600160a01b900460ff1681565b611e1a83838360405180602001604052806000815250612d90565b606080859050606085905060608590506060859050606081518351855187510101016040519080825280601f01601f19166020018201604052801561201c576020820181803883390190505b509050806000805b87518110156120755787818151811061203957fe5b602001015160f81c60f81b83838060010194508151811061205657fe5b60200101906001600160f81b031916908160001a905350600101612024565b5060005b86518110156120ca5786818151811061208e57fe5b602001015160f81c60f81b8383806001019450815181106120ab57fe5b60200101906001600160f81b031916908160001a905350600101612079565b5060005b855181101561211f578581815181106120e357fe5b602001015160f81c60f81b83838060010194508151811061210057fe5b60200101906001600160f81b031916908160001a9053506001016120ce565b5060005b84518110156121745784818151811061213857fe5b602001015160f81c60f81b83838060010194508151811061215557fe5b60200101906001600160f81b031916908160001a905350600101612123565b50909b9a5050505050505050505050565b607a6020526000908152604090205481565b606081806121be5750506040805180820190915260018152600360fc1b6020820152611526565b8260005b81156121d657600101600a820491506121c2565b6060816040519080825280601f01601f191660200182016040528015612203576020820181803883390190505b50905060001982015b841561225157600a850660300160f81b8282806001900393508151811061222f57fe5b60200101906001600160f81b031916908160001a905350600a8504945061220c565b5095945050505050565b60006115f482613b8b565b61226e61283c565b61227757600080fd5b611e1a60718383614390565b604080518082018252601081526f181899199a1a9b1b9c1cb0b131b232b360811b60208201528151602a80825260608281019094526001600160a01b03851692918491602082018180388339019050509050600360fc1b816000815181106122e757fe5b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061231057fe5b60200101906001600160f81b031916908160001a90535060005b60148110156123f6578260048583600c016020811061234557fe5b1a60f81b6001600160f81b031916901c60f81c60ff168151811061236557fe5b602001015160f81c60f81b82826002026002018151811061238257fe5b60200101906001600160f81b031916908160001a905350828482600c01602081106123a957fe5b825191901a600f169081106123ba57fe5b602001015160f81c60f81b8282600202600301815181106123d757fe5b60200101906001600160f81b031916908160001a90535060010161232a565b50949350505050565b336000908152607a6020526040902080546001019055565b6000818152606f602052604081205482906001600160a01b0316612470576040805162461bcd60e51b815260206004820152600b60248201526a4e4f5f535543485f4b455960a81b604482015290519081900360640190fd5b50506000908152606f60205260409020546001600160a01b031690565b6001600160a01b03166000908152606e6020526040902060010154421090565b60006001600160a01b0382166124fc576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b6125058261248d565b612510576000612513565b60015b60ff1692915050565b606754600160a01b900460ff1661256c576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b806125768161248d565b6125b7576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b611e1a8383613c6a565b6125c961283c565b6125d257600080fd5b6034546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603480546001600160a01b0319169055565b606b5481565b61262a61283c565b61263357600080fd5b61263f60728383614390565b507f8868e22e84ebf32da89b2ebcb0ac642816304ea3863b257f240df9098719cb97828260405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a15050565b6126ac61283c565b6126b557600080fd5b60005b838110156126ff576126f78585838181106126cf57fe5b905060200201356001600160a01b03168484848181106126eb57fe5b90506020020135613f35565b6001016126b8565b5050505050565b6000816127128161248d565b612753576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b600061275e84613842565b905060004282600101540390506000606954821061277f5750606a546127a0565b606954606a54612795908463ffffffff61403516565b8161279c57fe5b0490505b6077546076546127b790839063ffffffff61403516565b816127be57fe5b049695505050505050565b6001600160a01b03919091166000908152607a602090815260409182902054825130606090811b82850152603482019290925293901b6bffffffffffffffffffffffff19166054840152815180840360480181526068909301909152815191012090565b6034546001600160a01b031690565b6034546001600160a01b0316331490565b60765481565b60705490565b6072546060906002600019610100600184161502019091160461295257606860009054906101000a90046001600160a01b03166001600160a01b03166335a750de6040518163ffffffff1660e01b815260040160006040518083038186803b1580156128c457600080fd5b505afa1580156128d8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561290157600080fd5b810190808051600160201b81111561291857600080fd5b8201602081018481111561292b57600080fd5b8151600160201b81118282018710171561294457600080fd5b509094506115e69350505050565b6072805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156129d85780601f106129ad576101008083540402835291602001916129d8565b820191906000526020600020905b8154815290600101906020018083116129bb57829003601f168201915b505050505090506115e6565b6000816129f08161248d565b612a31576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b50506001600160a01b03166000908152606e602052604090205490565b6000918252606f6020526040909120546001600160a01b0391821691161490565b612a7761283c565b612a8057600080fd5b612a8a8282613f35565b5050565b6067546001600160a01b031681565b612aa561283c565b612aae57600080fd5b80612ab88161248d565b612af9576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b6001600160a01b0382166000908152606e602090815260409182902042600182015580548351908152925190927f59f2fe866dd27a1c2d34115520888c3150365cbc931aab97fa88c4b9ab40b79592908290030190a1505050565b606754600160a01b900460ff16612ba4576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b6001600160a01b038216331415612bf1576040805162461bcd60e51b815260206004820152600c60248201526b20a8282927ab22afa9a2a62360a11b604482015290519081900360640190fd5b3360008181526075602090815260408083206001600160a01b03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b612c6761283c565b612c7057600080fd5b606754600160a01b900460ff1615612cbf576040805162461bcd60e51b815260206004820152600d60248201526c111254d050931157d1925494d5609a1b604482015290519081900360640190fd5b6040805130318152905133917fa053f2a7eceda47dde76e5939c5adf7b771e665fc84c8ef6feffc290a1eb1feb919081900360200190a2612d0833612d0330613442565b61397f565b33ff5b6001600160a01b0381166000908152606e60205260408120600101548290612d70576040805162461bcd60e51b81526020600482015260136024820152724841535f4e455645525f4f574e45445f4b455960681b604482015290519081900360640190fd5b50506001600160a01b03166000908152606e602052604090206001015490565b606754600160a01b900460ff16612de0576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b81612deb8133612a4e565b80612dfb5750612dfb813361358f565b80612e0d5750612e0d61167782612417565b612e5b576040805162461bcd60e51b815260206004820152601a60248201527913d3931657d2d15657d3d5d3915497d3d497d054141493d5915160321b604482015290519081900360640190fd5b612e6483612417565b612e6d8161248d565b612eae576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b612eb9868686611a81565b612ec58686868661408e565b612f16576040805162461bcd60e51b815260206004820152601d60248201527f4e4f4e5f434f4d504c49414e545f4552433732315f5245434549564552000000604482015290519081900360640190fd5b505050505050565b826001600160a01b0316612f79612f3d612f3886336127c9565b6141c1565b84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061421292505050565b6001600160a01b031614612fc8576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f5349474e415455524560781b604482015290519081900360640190fd5b6001600160a01b0383166000908152607a6020526040902080546001019055611e1a836135b0565b612ff861283c565b61300157600080fd5b606754600160a01b900460ff16613051576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b6040517f25a311358326fb18c62efc24bc28d3126acee8d2a67fd8b2145b757dc8bd1bc190600090a16067805460ff60a01b19169055565b600154610100900460ff16806130a257506130a2614300565b806130b0575060015460ff16155b6130eb5760405162461bcd60e51b815260040180806020018281038252602e81526020018061444a602e913960400191505060405180910390fd5b600154610100900460ff16158015613115576001805460ff1961ff00199091166101001716811790555b603480546001600160a01b0319166001600160a01b0384811691909117918290556040519116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a38015612a8a576001805461ff00191690555050565b6000818152606f602052604090205460609082906001600160a01b03166131d5576040805162461bcd60e51b815260206004820152600b60248201526a4e4f5f535543485f4b455960a81b604482015290519081900360640190fd5b607354606090600260001961010060018416150201909116046132ce57606860009054906101000a90046001600160a01b03166001600160a01b0316637ff94bb26040518163ffffffff1660e01b815260040160006040518083038186803b15801561324057600080fd5b505afa158015613254573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561327d57600080fd5b810190808051600160201b81111561329457600080fd5b820160208101848111156132a757600080fd5b8151600160201b8111828201871017156132c057600080fd5b5090945061335c9350505050565b6073805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156133545780601f1061332957610100808354040283529160200191613354565b820191906000526020600020905b81548152906001019060200180831161333757829003601f168201915b505050505090505b6119c08161336930612283565b604051806040016040528060018152602001602f60f81b81525061338c88612197565b611fd0565b600490565b60775481565b6001600160a01b03918216600090815260756020908152604080832093909416825291909152205460ff1690565b6133d261283c565b6133db57600080fd5b6133e481614306565b50565b606754600160a01b900460ff16613437576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b6133e4816000613c6a565b6067546000906001600160a01b031661346657506001600160a01b03811631611526565b606754604080516370a0823160e01b81526001600160a01b038581166004830152915191909216916370a08231916024808301926020929190829003018186803b1580156134b357600080fd5b505afa1580156134c7573d6000803e3d6000fd5b505050506040513d60208110156134dd57600080fd5b50519050611526565b6134ee61283c565b6134f757600080fd5b60005b8281101561352f5761352784848381811061351157fe5b905060200201356001600160a01b031683613f35565b6001016134fa565b50505050565b6000818152607460205260408120546001600160a01b0316806115f4576040805162461bcd60e51b815260206004820152600d60248201526c1393d39157d054141493d59151609a1b604482015290519081900360640190fd5b600091825260746020526040909120546001600160a01b0391821691161490565b60006135bb82613842565b905060006135c883613b8b565b825460408051838152905192935033926001600160a01b03871692917f0a7068a9989857441c039a14a42b67ed71dd1fcfe5a9b17cc87b252e47bce528919081900360200190a44260018301558015611e1a57611e1a338261397f565b80156133e4576067546001600160a01b03166136885780341015613683576040805162461bcd60e51b815260206004820152601060248201526f4e4f545f454e4f5547485f46554e445360801b604482015290519081900360640190fd5b6133e4565b606754604080516370a0823160e01b815230600482015290516001600160a01b039092169160009183916370a0823191602480820192602092909190829003018186803b1580156136d857600080fd5b505afa1580156136ec573d6000803e3d6000fd5b505050506040513d602081101561370257600080fd5b5051604080516323b872dd60e01b81523360048201523060248201526044810186905290519192506001600160a01b038416916323b872dd916064808201926020929091908290030181600087803b15801561375d57600080fd5b505af1158015613771573d6000803e3d6000fd5b505050506040513d602081101561378757600080fd5b5050604080516370a0823160e01b8152306004820152905182916001600160a01b038516916370a0823191602480820192602092909190829003018186803b1580156137d257600080fd5b505afa1580156137e6573d6000803e3d6000fd5b505050506040513d60208110156137fc57600080fd5b505111611e1a576040805162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b604482015290519081900360640190fd5b6001600160a01b03166000908152606e6020526040902090565b6000818152606f60205260409020546001600160a01b03838116911614612a8a5760708054600181019091557f8f6b23ffa15f0465e3176e15ca644cf24f86dc1312fe715484e3c4aead5eb78b0180546001600160a01b0384166001600160a01b031991821681179092556000838152606f60205260409020805490911690911790555050565b60008282018381101561393d576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000818152607460205260409020546001600160a01b0316156133e457600090815260746020526040902080546001600160a01b0319169055565b8015612a8a576067546001600160a01b03166139d1576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156139cb573d6000803e3d6000fd5b50612a8a565b606754604080516370a0823160e01b81526001600160a01b0385811660048301529151919092169160009183916370a08231916024808301926020929190829003018186803b158015613a2357600080fd5b505afa158015613a37573d6000803e3d6000fd5b505050506040513d6020811015613a4d57600080fd5b50516040805163a9059cbb60e01b81526001600160a01b0387811660048301526024820187905291519293509084169163a9059cbb916044808201926020929091908290030181600087803b158015613aa557600080fd5b505af1158015613ab9573d6000803e3d6000fd5b505050506040513d6020811015613acf57600080fd5b5050604080516370a0823160e01b81526001600160a01b038681166004830152915183928516916370a08231916024808301926020929190829003018186803b158015613b1b57600080fd5b505afa158015613b2f573d6000803e3d6000fd5b505050506040513d6020811015613b4557600080fd5b50511161352f576040805162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b604482015290519081900360640190fd5b600081613b978161248d565b613bd8576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b6000613be384613842565b905060004282600101540390506069548110613c0357606a549350613c24565b606954606a54613c19908363ffffffff61403516565b81613c2057fe5b0493505b6000607954613c40607854606a5461403590919063ffffffff16565b81613c4757fe5b04905080851115613c5c578085039450613c61565b600094505b50505050919050565b606c54606b5411613cb2576040805162461bcd60e51b815260206004820152600d60248201526c1313d0d2d7d4d3d31117d3d555609a1b604482015290519081900360640190fd5b6001600160a01b038216613cff576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b606a5460685460408051630cb175e360e01b81526001600160a01b03868116600483015260248201859052825160009586959094921692630cb175e3926044808301939192829003018186803b158015613d5857600080fd5b505afa158015613d6c573d6000803e3d6000fd5b505050506040513d6040811015613d8257600080fd5b50805160209091015190935091508080841115613da157506000613da6565b508281035b6000613db187613842565b8054909150613dd157613dc381614375565b613dd187826000015461385c565b42816001015410613dfd576069546001820154613df39163ffffffff6138e316565b6001820155613e08565b606954420160018201555b8415613e7b5760685460408051633652466360e01b8152600481018890526024810187905290516001600160a01b039092169163365246639160448082019260009290919082900301818387803b158015613e6257600080fd5b505af1158015613e76573d6000803e3d6000fd5b505050505b6068546040805163939d9f1f60e01b8152600481018590526001600160a01b0389811660248301529151919092169163939d9f1f91604480830192600092919082900301818387803b158015613ed057600080fd5b505af1158015613ee4573d6000803e3d6000fd5b5050606c546040519092506001600160a01b038a1691506000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4613f2c82613625565b50505050505050565b6001600160a01b038216613f82576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b6000613f8d83613842565b905080600101548211613fda576040805162461bcd60e51b815260206004820152601060248201526f414c52454144595f4f574e535f4b455960801b604482015290519081900360640190fd5b613fe381614375565b613ff183826000015461385c565b6001810182905580546040516001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b600082614044575060006115f4565b8282028284828161405157fe5b041461393d5760405162461bcd60e51b81526004018080602001828103825260218152602001806144296021913960400191505060405180910390fd5b60006140a2846001600160a01b031661438a565b6140ae575060016119c0565b604051630a85bd0160e11b815233600482018181526001600160a01b03888116602485015260448401879052608060648501908152865160848601528651600095928a169463150b7a029490938c938b938b939260a4019060208501908083838e5b83811015614128578181015183820152602001614110565b50505050905090810190601f1680156141555780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561417757600080fd5b505af115801561418b573d6000803e3d6000fd5b505050506040513d60208110156141a157600080fd5b50516001600160e01b031916630a85bd0160e11b14915050949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b60008151604114614225575060006115f4565b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561426b57600093505050506115f4565b8060ff16601b1415801561428357508060ff16601c14155b1561429457600093505050506115f4565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa1580156142eb573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b303b1590565b6001600160a01b03811661431957600080fd5b6034546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603480546001600160a01b0319166001600160a01b0392909216919091179055565b80546133e457606c8054600101908190559055565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106143d15782800160ff198235161785556143fe565b828001600101855582156143fe579182015b828111156143fe5782358255916020019190600101906143e3565b5061440a92915061440e565b5090565b6115e691905b8082111561440a576000815560010161441456fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564a265627a7a7230582047f15e51181351647a87d6980e0f8f20a1f88485a060e1fd9ce02eb8828eb7b464736f6c63430005090032436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564000000000000000000000000c0f32eba9a4192d93209e83e03b95be7f81036d700000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000aad08158cd000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000094644432031204461790000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106103e45760003560e01c80636d8ea5b4116102085780639d76ea5811610118578063c4d66de8116100ab578063e985e9c51161007a578063e985e9c5146113c6578063f2fde38b14611401578063f6e4641f14611434578063f8b2cb4f1461145a578063f8faf9421461148d576103e4565b8063c4d66de814611328578063c87b56dd1461135b578063d1bbd49c14611385578063d42cfc41146113b1576103e4565b8063abdf82ce116100e7578063abdf82ce14611191578063b88d4fde146111c4578063b8968bb414611288578063c1c98d0314611313576103e4565b80639d76ea58146110f95780639f98d3cb1461110e578063a22cb46514611141578063a843a4e71461117c576103e4565b80638d0361fc1161019b57806393fd18441161016a57806393fd18441461102a57806395d89b411461103f578063970aaeb714611054578063994a8a71146110875780639b3f0b17146110c0576103e4565b80638d0361fc14610fb05780638da5cb5b14610feb5780638f32d59b146110005780638f98ce8f14611015576103e4565b806374b6c106116101d757806374b6c10614610e22578063782a4ade14610e375780637c7c425314610eb257806383cb0fa914610f7d576103e4565b80636d8ea5b414610d7957806370a0823114610dac57806370efb77014610ddf578063715018a614610e0d576103e4565b806323b872dd1161030357806342842e0e1161029657806352d6a8e41161026557806352d6a8e414610c59578063550ef3a814610c8c5780635fdb97e114610d07578063627cdcb914610d3a5780636352211e14610d4f576103e4565b806342842e0e1461098657806345e965cd146109bc5780634bc5a13514610bfc5780634c7a12a014610c2f576103e4565b806339f46986116102d257806339f46986146108fc5780633ba70e311461092c5780633d3359cb146109415780634136aa3514610971576103e4565b806323b872dd1461080c5780632e1a7d4d1461084257806330176e131461086c57806338af3eed146108e7576103e4565b80630f15023b1161037b578063150b7a021161034a578063150b7a02146106ca57806318160ddd146107b85780631f1ec029146107cd5780632009dc65146107f7576103e4565b80630f15023b1461060b57806310803b721461062057806310e56973146106a057806311a4c03a146106b5576103e4565b8063095ea7b3116103b7578063095ea7b31461056e5780630aaffd2a1461059c5780630c79130f146105cf5780630ed3e2cc146105f6576103e4565b806301ffc9a71461042c578063025e7c271461047457806306fdde03146104ba578063081812fc14610544575b3480156103f057600080fd5b506040805162461bcd60e51b815260206004820152600b60248201526a4e4f5f46414c4c4241434b60a81b604482015290519081900360640190fd5b34801561043857600080fd5b506104606004803603602081101561044f57600080fd5b50356001600160e01b031916611508565b604080519115158252519081900360200190f35b34801561048057600080fd5b5061049e6004803603602081101561049757600080fd5b503561152b565b604080516001600160a01b039092168252519081900360200190f35b3480156104c657600080fd5b506104cf611552565b6040805160208082528351818301528351919283929083019185019080838360005b838110156105095781810151838201526020016104f1565b50505050905090810190601f1680156105365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561055057600080fd5b5061049e6004803603602081101561056757600080fd5b50356115e9565b61059a6004803603604081101561058457600080fd5b506001600160a01b0381351690602001356115fa565b005b3480156105a857600080fd5b5061059a600480360360208110156105bf57600080fd5b50356001600160a01b0316611787565b3480156105db57600080fd5b506105e4611878565b60408051918252519081900360200190f35b34801561060257600080fd5b506105e461187e565b34801561061757600080fd5b5061049e611884565b34801561062c57600080fd5b506106506004803603604081101561064357600080fd5b5080359060200135611893565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561068c578181015183820152602001610674565b505050509050019250505060405180910390f35b3480156106ac57600080fd5b506105e46119ab565b3480156106c157600080fd5b506105e46119b1565b3480156106d657600080fd5b5061079b600480360360808110156106ed57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561072757600080fd5b82018360208201111561073957600080fd5b803590602001918460018302840111600160201b8311171561075a57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506119b7945050505050565b604080516001600160e01b03199092168252519081900360200190f35b3480156107c457600080fd5b506105e46119c8565b3480156107d957600080fd5b5061059a600480360360208110156107f057600080fd5b50356119ce565b34801561080357600080fd5b5061059a611a76565b61059a6004803603606081101561082257600080fd5b506001600160a01b03813581169160208101359091169060400135611a81565b34801561084e57600080fd5b5061059a6004803603602081101561086557600080fd5b5035611ccb565b34801561087857600080fd5b5061059a6004803603602081101561088f57600080fd5b810190602081018135600160201b8111156108a957600080fd5b8201836020820111156108bb57600080fd5b803590602001918460018302840111600160201b831117156108dc57600080fd5b509092509050611e1f565b3480156108f357600080fd5b5061049e611e3c565b34801561090857600080fd5b5061059a6004803603604081101561091f57600080fd5b5080359060200135611e4b565b34801561093857600080fd5b506105e4611ef5565b34801561094d57600080fd5b5061059a6004803603604081101561096457600080fd5b5080359060200135611efb565b34801561097d57600080fd5b50610460611fa5565b61059a6004803603606081101561099c57600080fd5b506001600160a01b03813581169160208101359091169060400135611fb5565b3480156109c857600080fd5b506104cf600480360360808110156109df57600080fd5b810190602081018135600160201b8111156109f957600080fd5b820183602082011115610a0b57600080fd5b803590602001918460018302840111600160201b83111715610a2c57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610a7e57600080fd5b820183602082011115610a9057600080fd5b803590602001918460018302840111600160201b83111715610ab157600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610b0357600080fd5b820183602082011115610b1557600080fd5b803590602001918460018302840111600160201b83111715610b3657600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610b8857600080fd5b820183602082011115610b9a57600080fd5b803590602001918460018302840111600160201b83111715610bbb57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611fd0945050505050565b348015610c0857600080fd5b506105e460048036036020811015610c1f57600080fd5b50356001600160a01b0316612185565b348015610c3b57600080fd5b506104cf60048036036020811015610c5257600080fd5b5035612197565b348015610c6557600080fd5b506105e460048036036020811015610c7c57600080fd5b50356001600160a01b031661225b565b348015610c9857600080fd5b5061059a60048036036020811015610caf57600080fd5b810190602081018135600160201b811115610cc957600080fd5b820183602082011115610cdb57600080fd5b803590602001918460018302840111600160201b83111715610cfc57600080fd5b509092509050612266565b348015610d1357600080fd5b506104cf60048036036020811015610d2a57600080fd5b50356001600160a01b0316612283565b348015610d4657600080fd5b5061059a6123ff565b348015610d5b57600080fd5b5061049e60048036036020811015610d7257600080fd5b5035612417565b348015610d8557600080fd5b5061046060048036036020811015610d9c57600080fd5b50356001600160a01b031661248d565b348015610db857600080fd5b506105e460048036036020811015610dcf57600080fd5b50356001600160a01b03166124ad565b61059a60048036036040811015610df557600080fd5b506001600160a01b038135811691602001351661251c565b348015610e1957600080fd5b5061059a6125c1565b348015610e2e57600080fd5b506105e461261c565b348015610e4357600080fd5b5061059a60048036036020811015610e5a57600080fd5b810190602081018135600160201b811115610e7457600080fd5b820183602082011115610e8657600080fd5b803590602001918460018302840111600160201b83111715610ea757600080fd5b509092509050612622565b348015610ebe57600080fd5b5061059a60048036036040811015610ed557600080fd5b810190602081018135600160201b811115610eef57600080fd5b820183602082011115610f0157600080fd5b803590602001918460208302840111600160201b83111715610f2257600080fd5b919390929091602081019035600160201b811115610f3f57600080fd5b820183602082011115610f5157600080fd5b803590602001918460208302840111600160201b83111715610f7257600080fd5b5090925090506126a4565b348015610f8957600080fd5b506105e460048036036020811015610fa057600080fd5b50356001600160a01b0316612706565b348015610fbc57600080fd5b506105e460048036036040811015610fd357600080fd5b506001600160a01b03813581169160200135166127c9565b348015610ff757600080fd5b5061049e61282d565b34801561100c57600080fd5b5061046061283c565b34801561102157600080fd5b506105e461284d565b34801561103657600080fd5b506105e4612853565b34801561104b57600080fd5b506104cf612859565b34801561106057600080fd5b506105e46004803603602081101561107757600080fd5b50356001600160a01b03166129e4565b34801561109357600080fd5b50610460600480360360408110156110aa57600080fd5b50803590602001356001600160a01b0316612a4e565b3480156110cc57600080fd5b5061059a600480360360408110156110e357600080fd5b506001600160a01b038135169060200135612a6f565b34801561110557600080fd5b5061049e612a8e565b34801561111a57600080fd5b5061059a6004803603602081101561113157600080fd5b50356001600160a01b0316612a9d565b34801561114d57600080fd5b5061059a6004803603604081101561116457600080fd5b506001600160a01b0381351690602001351515612b54565b34801561118857600080fd5b5061059a612c5f565b34801561119d57600080fd5b506105e4600480360360208110156111b457600080fd5b50356001600160a01b0316612d0b565b61059a600480360360808110156111da57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561121457600080fd5b82018360208201111561122657600080fd5b803590602001918460018302840111600160201b8311171561124757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612d90945050505050565b34801561129457600080fd5b5061059a600480360360408110156112ab57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156112d557600080fd5b8201836020820111156112e757600080fd5b803590602001918460018302840111600160201b8311171561130857600080fd5b509092509050612f1e565b34801561131f57600080fd5b5061059a612ff0565b34801561133457600080fd5b5061059a6004803603602081101561134b57600080fd5b50356001600160a01b0316613089565b34801561136757600080fd5b506104cf6004803603602081101561137e57600080fd5b5035613179565b34801561139157600080fd5b5061139a613391565b6040805161ffff9092168252519081900360200190f35b3480156113bd57600080fd5b506105e4613396565b3480156113d257600080fd5b50610460600480360360408110156113e957600080fd5b506001600160a01b038135811691602001351661339c565b34801561140d57600080fd5b5061059a6004803603602081101561142457600080fd5b50356001600160a01b03166133ca565b61059a6004803603602081101561144a57600080fd5b50356001600160a01b03166133e7565b34801561146657600080fd5b506105e46004803603602081101561147d57600080fd5b50356001600160a01b0316613442565b34801561149957600080fd5b5061059a600480360360408110156114b057600080fd5b810190602081018135600160201b8111156114ca57600080fd5b8201836020820111156114dc57600080fd5b803590602001918460208302840111600160201b831117156114fd57600080fd5b9193509150356134e6565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b6070818154811061153857fe5b6000918252602090912001546001600160a01b0316905081565b60718054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156115de5780601f106115b3576101008083540402835291602001916115de565b820191906000526020600020905b8154815290600101906020018083116115c157829003601f168201915b505050505090505b90565b60006115f482613535565b92915050565b606754600160a01b900460ff1661164a576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b806116558133612a4e565b806116655750611665813361358f565b8061167d575061167d61167782612417565b3361339c565b6116cb576040805162461bcd60e51b815260206004820152601a60248201527913d3931657d2d15657d3d5d3915497d3d497d054141493d5915160321b604482015290519081900360640190fd5b336001600160a01b0384161415611718576040805162461bcd60e51b815260206004820152600c60248201526b20a8282927ab22afa9a2a62360a11b604482015290519081900360640190fd5b600082815260746020526040902080546001600160a01b0319166001600160a01b038516908117909155829061174d82612417565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b61178f61282d565b6001600160a01b0316336001600160a01b031614806117b85750606d546001600160a01b031633145b611809576040805162461bcd60e51b815260206004820152601e60248201527f4f4e4c595f4c4f434b5f4f574e45525f4f525f42454e45464943494152590000604482015290519081900360640190fd5b6001600160a01b038116611856576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b606d80546001600160a01b0319166001600160a01b0392909216919091179055565b60795481565b60785481565b6068546001600160a01b031681565b6070546060906118e0576040805162461bcd60e51b81526020600482015260136024820152724e4f5f4f55545354414e44494e475f4b45595360681b604482015290519081900360640190fd5b607054829084820290600090828401111561190357506070548181039250611908565b508082015b606083604051908082528060200260200182016040528015611934578160200160208202803883390190505b5090506000835b8381101561199e576070818154811061195057fe5b9060005260206000200160009054906101000a90046001600160a01b031683838151811061197a57fe5b6001600160a01b03909216602092830291909101909101526001918201910161193b565b5090979650505050505050565b606a5481565b60695481565b630a85bd0160e11b5b949350505050565b606c5490565b6119d661283c565b6119df57600080fd5b606754600160a01b900460ff16611a2f576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b606a805490829055604080518281526020810184905281517f8aa4fa52648a6d15edce8a179c792c86f3719d0cc3c572cf90f91948f0f2cb68929181900390910190a15050565b611a7f336135b0565b565b606754600160a01b900460ff16611ad1576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b82611adb8161248d565b611b1c576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b81611b278133612a4e565b80611b375750611b37813361358f565b80611b495750611b4961167782612417565b611b97576040805162461bcd60e51b815260206004820152601a60248201527913d3931657d2d15657d3d5d3915497d3d497d054141493d5915160321b604482015290519081900360640190fd5b6001600160a01b038416611be4576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b611bf5611bf086612706565b613625565b6000611c0086613842565b90506000611c0d86613842565b6001810154815491925090611c2c578254808355611c2c90889061385c565b428111611c50576001808401549083015582548255611c4b878761385c565b611c6d565b6001830154611c679042830363ffffffff6138e316565b60018301555b42600184015560008355611c8086613944565b85876001600160a01b0316896001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050505050565b611cd361282d565b6001600160a01b0316336001600160a01b03161480611cfc5750606d546001600160a01b031633145b611d4d576040805162461bcd60e51b815260206004820152601e60248201527f4f4e4c595f4c4f434b5f4f574e45525f4f525f42454e45464943494152590000604482015290519081900360640190fd5b6000611d5830613442565b90506000821580611d6857508183115b15611dbc5760008211611db5576040805162461bcd60e51b815260206004820152601060248201526f4e4f545f454e4f5547485f46554e445360801b604482015290519081900360640190fd5b5080611dbf565b50815b606d546040805183815290516001600160a01b039092169133917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398919081900360200190a3606d54611e1a906001600160a01b03168261397f565b505050565b611e2761283c565b611e3057600080fd5b611e1a60738383614390565b606d546001600160a01b031681565b611e5361283c565b611e5c57600080fd5b80611e9d576040805162461bcd60e51b815260206004820152600c60248201526b494e56414c49445f5241544560a01b604482015290519081900360640190fd5b60785460795460408051928352602083019190915281810184905260608201839052517fa7d13855fe99b8c8b2780f36ff9e06133878b66a664a951b2375fe2296cc00089181900360800190a1607891909155607955565b606c5481565b611f0361283c565b611f0c57600080fd5b80611f4d576040805162461bcd60e51b815260206004820152600c60248201526b494e56414c49445f5241544560a01b604482015290519081900360640190fd5b60765460775460408051928352602083019190915281810184905260608201839052517ff0cc3b8bd450a20cce7720453e064b35cf490baa5d53c7c6ef8b2e1b02898a7d9181900360800190a1607691909155607755565b606754600160a01b900460ff1681565b611e1a83838360405180602001604052806000815250612d90565b606080859050606085905060608590506060859050606081518351855187510101016040519080825280601f01601f19166020018201604052801561201c576020820181803883390190505b509050806000805b87518110156120755787818151811061203957fe5b602001015160f81c60f81b83838060010194508151811061205657fe5b60200101906001600160f81b031916908160001a905350600101612024565b5060005b86518110156120ca5786818151811061208e57fe5b602001015160f81c60f81b8383806001019450815181106120ab57fe5b60200101906001600160f81b031916908160001a905350600101612079565b5060005b855181101561211f578581815181106120e357fe5b602001015160f81c60f81b83838060010194508151811061210057fe5b60200101906001600160f81b031916908160001a9053506001016120ce565b5060005b84518110156121745784818151811061213857fe5b602001015160f81c60f81b83838060010194508151811061215557fe5b60200101906001600160f81b031916908160001a905350600101612123565b50909b9a5050505050505050505050565b607a6020526000908152604090205481565b606081806121be5750506040805180820190915260018152600360fc1b6020820152611526565b8260005b81156121d657600101600a820491506121c2565b6060816040519080825280601f01601f191660200182016040528015612203576020820181803883390190505b50905060001982015b841561225157600a850660300160f81b8282806001900393508151811061222f57fe5b60200101906001600160f81b031916908160001a905350600a8504945061220c565b5095945050505050565b60006115f482613b8b565b61226e61283c565b61227757600080fd5b611e1a60718383614390565b604080518082018252601081526f181899199a1a9b1b9c1cb0b131b232b360811b60208201528151602a80825260608281019094526001600160a01b03851692918491602082018180388339019050509050600360fc1b816000815181106122e757fe5b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061231057fe5b60200101906001600160f81b031916908160001a90535060005b60148110156123f6578260048583600c016020811061234557fe5b1a60f81b6001600160f81b031916901c60f81c60ff168151811061236557fe5b602001015160f81c60f81b82826002026002018151811061238257fe5b60200101906001600160f81b031916908160001a905350828482600c01602081106123a957fe5b825191901a600f169081106123ba57fe5b602001015160f81c60f81b8282600202600301815181106123d757fe5b60200101906001600160f81b031916908160001a90535060010161232a565b50949350505050565b336000908152607a6020526040902080546001019055565b6000818152606f602052604081205482906001600160a01b0316612470576040805162461bcd60e51b815260206004820152600b60248201526a4e4f5f535543485f4b455960a81b604482015290519081900360640190fd5b50506000908152606f60205260409020546001600160a01b031690565b6001600160a01b03166000908152606e6020526040902060010154421090565b60006001600160a01b0382166124fc576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b6125058261248d565b612510576000612513565b60015b60ff1692915050565b606754600160a01b900460ff1661256c576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b806125768161248d565b6125b7576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b611e1a8383613c6a565b6125c961283c565b6125d257600080fd5b6034546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603480546001600160a01b0319169055565b606b5481565b61262a61283c565b61263357600080fd5b61263f60728383614390565b507f8868e22e84ebf32da89b2ebcb0ac642816304ea3863b257f240df9098719cb97828260405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a15050565b6126ac61283c565b6126b557600080fd5b60005b838110156126ff576126f78585838181106126cf57fe5b905060200201356001600160a01b03168484848181106126eb57fe5b90506020020135613f35565b6001016126b8565b5050505050565b6000816127128161248d565b612753576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b600061275e84613842565b905060004282600101540390506000606954821061277f5750606a546127a0565b606954606a54612795908463ffffffff61403516565b8161279c57fe5b0490505b6077546076546127b790839063ffffffff61403516565b816127be57fe5b049695505050505050565b6001600160a01b03919091166000908152607a602090815260409182902054825130606090811b82850152603482019290925293901b6bffffffffffffffffffffffff19166054840152815180840360480181526068909301909152815191012090565b6034546001600160a01b031690565b6034546001600160a01b0316331490565b60765481565b60705490565b6072546060906002600019610100600184161502019091160461295257606860009054906101000a90046001600160a01b03166001600160a01b03166335a750de6040518163ffffffff1660e01b815260040160006040518083038186803b1580156128c457600080fd5b505afa1580156128d8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561290157600080fd5b810190808051600160201b81111561291857600080fd5b8201602081018481111561292b57600080fd5b8151600160201b81118282018710171561294457600080fd5b509094506115e69350505050565b6072805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156129d85780601f106129ad576101008083540402835291602001916129d8565b820191906000526020600020905b8154815290600101906020018083116129bb57829003601f168201915b505050505090506115e6565b6000816129f08161248d565b612a31576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b50506001600160a01b03166000908152606e602052604090205490565b6000918252606f6020526040909120546001600160a01b0391821691161490565b612a7761283c565b612a8057600080fd5b612a8a8282613f35565b5050565b6067546001600160a01b031681565b612aa561283c565b612aae57600080fd5b80612ab88161248d565b612af9576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b6001600160a01b0382166000908152606e602090815260409182902042600182015580548351908152925190927f59f2fe866dd27a1c2d34115520888c3150365cbc931aab97fa88c4b9ab40b79592908290030190a1505050565b606754600160a01b900460ff16612ba4576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b6001600160a01b038216331415612bf1576040805162461bcd60e51b815260206004820152600c60248201526b20a8282927ab22afa9a2a62360a11b604482015290519081900360640190fd5b3360008181526075602090815260408083206001600160a01b03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b612c6761283c565b612c7057600080fd5b606754600160a01b900460ff1615612cbf576040805162461bcd60e51b815260206004820152600d60248201526c111254d050931157d1925494d5609a1b604482015290519081900360640190fd5b6040805130318152905133917fa053f2a7eceda47dde76e5939c5adf7b771e665fc84c8ef6feffc290a1eb1feb919081900360200190a2612d0833612d0330613442565b61397f565b33ff5b6001600160a01b0381166000908152606e60205260408120600101548290612d70576040805162461bcd60e51b81526020600482015260136024820152724841535f4e455645525f4f574e45445f4b455960681b604482015290519081900360640190fd5b50506001600160a01b03166000908152606e602052604090206001015490565b606754600160a01b900460ff16612de0576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b81612deb8133612a4e565b80612dfb5750612dfb813361358f565b80612e0d5750612e0d61167782612417565b612e5b576040805162461bcd60e51b815260206004820152601a60248201527913d3931657d2d15657d3d5d3915497d3d497d054141493d5915160321b604482015290519081900360640190fd5b612e6483612417565b612e6d8161248d565b612eae576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b612eb9868686611a81565b612ec58686868661408e565b612f16576040805162461bcd60e51b815260206004820152601d60248201527f4e4f4e5f434f4d504c49414e545f4552433732315f5245434549564552000000604482015290519081900360640190fd5b505050505050565b826001600160a01b0316612f79612f3d612f3886336127c9565b6141c1565b84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061421292505050565b6001600160a01b031614612fc8576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f5349474e415455524560781b604482015290519081900360640190fd5b6001600160a01b0383166000908152607a6020526040902080546001019055611e1a836135b0565b612ff861283c565b61300157600080fd5b606754600160a01b900460ff16613051576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b6040517f25a311358326fb18c62efc24bc28d3126acee8d2a67fd8b2145b757dc8bd1bc190600090a16067805460ff60a01b19169055565b600154610100900460ff16806130a257506130a2614300565b806130b0575060015460ff16155b6130eb5760405162461bcd60e51b815260040180806020018281038252602e81526020018061444a602e913960400191505060405180910390fd5b600154610100900460ff16158015613115576001805460ff1961ff00199091166101001716811790555b603480546001600160a01b0319166001600160a01b0384811691909117918290556040519116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a38015612a8a576001805461ff00191690555050565b6000818152606f602052604090205460609082906001600160a01b03166131d5576040805162461bcd60e51b815260206004820152600b60248201526a4e4f5f535543485f4b455960a81b604482015290519081900360640190fd5b607354606090600260001961010060018416150201909116046132ce57606860009054906101000a90046001600160a01b03166001600160a01b0316637ff94bb26040518163ffffffff1660e01b815260040160006040518083038186803b15801561324057600080fd5b505afa158015613254573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561327d57600080fd5b810190808051600160201b81111561329457600080fd5b820160208101848111156132a757600080fd5b8151600160201b8111828201871017156132c057600080fd5b5090945061335c9350505050565b6073805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156133545780601f1061332957610100808354040283529160200191613354565b820191906000526020600020905b81548152906001019060200180831161333757829003601f168201915b505050505090505b6119c08161336930612283565b604051806040016040528060018152602001602f60f81b81525061338c88612197565b611fd0565b600490565b60775481565b6001600160a01b03918216600090815260756020908152604080832093909416825291909152205460ff1690565b6133d261283c565b6133db57600080fd5b6133e481614306565b50565b606754600160a01b900460ff16613437576040805162461bcd60e51b815260206004820152600f60248201526e1313d0d2d7d11154149150d0551151608a1b604482015290519081900360640190fd5b6133e4816000613c6a565b6067546000906001600160a01b031661346657506001600160a01b03811631611526565b606754604080516370a0823160e01b81526001600160a01b038581166004830152915191909216916370a08231916024808301926020929190829003018186803b1580156134b357600080fd5b505afa1580156134c7573d6000803e3d6000fd5b505050506040513d60208110156134dd57600080fd5b50519050611526565b6134ee61283c565b6134f757600080fd5b60005b8281101561352f5761352784848381811061351157fe5b905060200201356001600160a01b031683613f35565b6001016134fa565b50505050565b6000818152607460205260408120546001600160a01b0316806115f4576040805162461bcd60e51b815260206004820152600d60248201526c1393d39157d054141493d59151609a1b604482015290519081900360640190fd5b600091825260746020526040909120546001600160a01b0391821691161490565b60006135bb82613842565b905060006135c883613b8b565b825460408051838152905192935033926001600160a01b03871692917f0a7068a9989857441c039a14a42b67ed71dd1fcfe5a9b17cc87b252e47bce528919081900360200190a44260018301558015611e1a57611e1a338261397f565b80156133e4576067546001600160a01b03166136885780341015613683576040805162461bcd60e51b815260206004820152601060248201526f4e4f545f454e4f5547485f46554e445360801b604482015290519081900360640190fd5b6133e4565b606754604080516370a0823160e01b815230600482015290516001600160a01b039092169160009183916370a0823191602480820192602092909190829003018186803b1580156136d857600080fd5b505afa1580156136ec573d6000803e3d6000fd5b505050506040513d602081101561370257600080fd5b5051604080516323b872dd60e01b81523360048201523060248201526044810186905290519192506001600160a01b038416916323b872dd916064808201926020929091908290030181600087803b15801561375d57600080fd5b505af1158015613771573d6000803e3d6000fd5b505050506040513d602081101561378757600080fd5b5050604080516370a0823160e01b8152306004820152905182916001600160a01b038516916370a0823191602480820192602092909190829003018186803b1580156137d257600080fd5b505afa1580156137e6573d6000803e3d6000fd5b505050506040513d60208110156137fc57600080fd5b505111611e1a576040805162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b604482015290519081900360640190fd5b6001600160a01b03166000908152606e6020526040902090565b6000818152606f60205260409020546001600160a01b03838116911614612a8a5760708054600181019091557f8f6b23ffa15f0465e3176e15ca644cf24f86dc1312fe715484e3c4aead5eb78b0180546001600160a01b0384166001600160a01b031991821681179092556000838152606f60205260409020805490911690911790555050565b60008282018381101561393d576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000818152607460205260409020546001600160a01b0316156133e457600090815260746020526040902080546001600160a01b0319169055565b8015612a8a576067546001600160a01b03166139d1576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156139cb573d6000803e3d6000fd5b50612a8a565b606754604080516370a0823160e01b81526001600160a01b0385811660048301529151919092169160009183916370a08231916024808301926020929190829003018186803b158015613a2357600080fd5b505afa158015613a37573d6000803e3d6000fd5b505050506040513d6020811015613a4d57600080fd5b50516040805163a9059cbb60e01b81526001600160a01b0387811660048301526024820187905291519293509084169163a9059cbb916044808201926020929091908290030181600087803b158015613aa557600080fd5b505af1158015613ab9573d6000803e3d6000fd5b505050506040513d6020811015613acf57600080fd5b5050604080516370a0823160e01b81526001600160a01b038681166004830152915183928516916370a08231916024808301926020929190829003018186803b158015613b1b57600080fd5b505afa158015613b2f573d6000803e3d6000fd5b505050506040513d6020811015613b4557600080fd5b50511161352f576040805162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b604482015290519081900360640190fd5b600081613b978161248d565b613bd8576040805162461bcd60e51b815260206004820152600d60248201526c12d15657d393d517d590531251609a1b604482015290519081900360640190fd5b6000613be384613842565b905060004282600101540390506069548110613c0357606a549350613c24565b606954606a54613c19908363ffffffff61403516565b81613c2057fe5b0493505b6000607954613c40607854606a5461403590919063ffffffff16565b81613c4757fe5b04905080851115613c5c578085039450613c61565b600094505b50505050919050565b606c54606b5411613cb2576040805162461bcd60e51b815260206004820152600d60248201526c1313d0d2d7d4d3d31117d3d555609a1b604482015290519081900360640190fd5b6001600160a01b038216613cff576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b606a5460685460408051630cb175e360e01b81526001600160a01b03868116600483015260248201859052825160009586959094921692630cb175e3926044808301939192829003018186803b158015613d5857600080fd5b505afa158015613d6c573d6000803e3d6000fd5b505050506040513d6040811015613d8257600080fd5b50805160209091015190935091508080841115613da157506000613da6565b508281035b6000613db187613842565b8054909150613dd157613dc381614375565b613dd187826000015461385c565b42816001015410613dfd576069546001820154613df39163ffffffff6138e316565b6001820155613e08565b606954420160018201555b8415613e7b5760685460408051633652466360e01b8152600481018890526024810187905290516001600160a01b039092169163365246639160448082019260009290919082900301818387803b158015613e6257600080fd5b505af1158015613e76573d6000803e3d6000fd5b505050505b6068546040805163939d9f1f60e01b8152600481018590526001600160a01b0389811660248301529151919092169163939d9f1f91604480830192600092919082900301818387803b158015613ed057600080fd5b505af1158015613ee4573d6000803e3d6000fd5b5050606c546040519092506001600160a01b038a1691506000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4613f2c82613625565b50505050505050565b6001600160a01b038216613f82576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b6000613f8d83613842565b905080600101548211613fda576040805162461bcd60e51b815260206004820152601060248201526f414c52454144595f4f574e535f4b455960801b604482015290519081900360640190fd5b613fe381614375565b613ff183826000015461385c565b6001810182905580546040516001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b600082614044575060006115f4565b8282028284828161405157fe5b041461393d5760405162461bcd60e51b81526004018080602001828103825260218152602001806144296021913960400191505060405180910390fd5b60006140a2846001600160a01b031661438a565b6140ae575060016119c0565b604051630a85bd0160e11b815233600482018181526001600160a01b03888116602485015260448401879052608060648501908152865160848601528651600095928a169463150b7a029490938c938b938b939260a4019060208501908083838e5b83811015614128578181015183820152602001614110565b50505050905090810190601f1680156141555780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561417757600080fd5b505af115801561418b573d6000803e3d6000fd5b505050506040513d60208110156141a157600080fd5b50516001600160e01b031916630a85bd0160e11b14915050949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b60008151604114614225575060006115f4565b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561426b57600093505050506115f4565b8060ff16601b1415801561428357508060ff16601c14155b1561429457600093505050506115f4565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa1580156142eb573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b303b1590565b6001600160a01b03811661431957600080fd5b6034546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603480546001600160a01b0319166001600160a01b0392909216919091179055565b80546133e457606c8054600101908190559055565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106143d15782800160ff198235161785556143fe565b828001600101855582156143fe579182015b828111156143fe5782358255916020019190600101906143e3565b5061440a92915061440e565b5090565b6115e691905b8082111561440a576000815560010161441456fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564a265627a7a7230582047f15e51181351647a87d6980e0f8f20a1f88485a060e1fd9ce02eb8828eb7b464736f6c63430005090032

Deployed Bytecode Sourcemap

72624:1064:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;47743:21:0;;;-1:-1:-1;;;47743:21:0;;;;;;;;;;;;-1:-1:-1;;;47743:21:0;;;;;;;;;;;;;;12092:135;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12092:135:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;12092:135:0;-1:-1:-1;;;;;;12092:135:0;;:::i;:::-;;;;;;;;;;;;;;;;;;30062:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30062:23:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30062:23:0;;:::i;:::-;;;;-1:-1:-1;;;;;30062:23:0;;;;;;;;;;;;;;45537:94;;8:9:-1;5:2;;;30:1;27;20:12;5:2;45537: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;45537:94:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38219:138;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38219:138:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;38219:138:0;;:::i;37249:311::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;37249:311:0;;;;;;;;:::i;:::-;;28391:199;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28391:199:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28391:199:0;-1:-1:-1;;;;;28391:199:0;;:::i;59330:41::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59330:41:0;;;:::i;:::-;;;;;;;;;;;;;;;;59287:38;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59287:38:0;;;:::i;25420:29::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25420:29:0;;;:::i;32352:879::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;32352:879:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;32352: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;32352:879:0;;;;;;;;;;;;;;;;;25795:20;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25795:20:0;;;:::i;25637:30::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25637:30:0;;;:::i;14281:147::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;14281:147:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;14281:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;14281:147:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;14281: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;14281:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;14281:147:0;;-1:-1:-1;14281:147:0;;-1:-1:-1;;;;;14281:147:0:i;:::-;;;;-1:-1:-1;;;;;;14281:147:0;;;;;;;;;;;;;;28714:104;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28714:104:0;;;:::i;28034:213::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28034:213:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28034:213:0;;:::i;59909:85::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59909:85:0;;;:::i;66538:1750::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;66538:1750:0;;;;;;;;;;;;;;;;;:::i;27405:517::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;27405:517:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;27405:517:0;;:::i;46290:134::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;46290:134:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;46290:134:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;46290:134:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;46290: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;46290:134:0;;-1:-1:-1;46290:134:0;-1:-1:-1;46290:134:0;:::i;26075:26::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;26075:26:0;;;:::i;60942:491::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60942:491:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;60942:491:0;;;;;;;:::i;25983:28::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25983:28:0;;;:::i;69844:463::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;69844:463:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;69844:463:0;;;;;;;:::i;20553:19::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;20553:19:0;;;:::i;68641:174::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;68641:174:0;;;;;;;;;;;;;;;;;:::i;42204:820::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42204:820:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;42204:820:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;42204:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42204: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;42204:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;42204:820:0;;;;;;;;-1:-1:-1;42204:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;42204:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42204: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;42204:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;42204:820:0;;;;;;;;-1:-1:-1;42204:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;42204:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42204: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;42204:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;42204:820:0;;;;;;;;-1:-1:-1;42204:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;42204:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42204: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;42204:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;42204:820:0;;-1:-1:-1;42204:820:0;;-1:-1:-1;;;;;42204:820:0:i;59435:47::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59435:47:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;59435:47:0;-1:-1:-1;;;;;59435:47:0;;:::i;43030:516::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43030:516:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43030:516:0;;:::i;61719:163::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;61719:163:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;61719:163:0;-1:-1:-1;;;;;61719:163:0;;:::i;45313:121::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;45313:121:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;45313:121:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;45313:121:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;45313: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;45313:121:0;;-1:-1:-1;45313:121:0;-1:-1:-1;45313:121:0;:::i;43552:457::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43552:457:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43552:457:0;-1:-1:-1;;;;;43552:457:0;;:::i;60786:84::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60786:84:0;;;:::i;34217:150::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34217:150:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;34217:150:0;;:::i;31653:171::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;31653:171:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;31653:171:0;-1:-1:-1;;;;;31653:171:0;;:::i;31388:197::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;31388:197:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;31388:197:0;-1:-1:-1;;;;;31388:197:0;;:::i;52435:209::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;52435:209:0;;;;;;;;;;:::i;9442:140::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9442:140:0;;;:::i;25889:27::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25889:27:0;;;:::i;45713:167::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;45713:167:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;45713:167:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;45713:167:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;45713: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;45713:167:0;;-1:-1:-1;45713:167:0;-1:-1:-1;45713:167:0;:::i;41032:257::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41032:257:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;41032:257:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;41032:257:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;41032: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;41032:257:0;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;41032:257:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;41032: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;41032:257:0;;-1:-1:-1;41032:257:0;-1:-1:-1;41032:257:0;:::i;70572:727::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;70572:727:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;70572:727:0;-1:-1:-1;;;;;70572:727:0;;:::i;61995:456::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;61995:456:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;61995:456:0;;;;;;;;;;:::i;8729:79::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8729:79:0;;;:::i;9064:92::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9064:92:0;;;:::i;66310:36::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66310:36:0;;;:::i;33982:104::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;33982:104:0;;;:::i;45985:215::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;45985:215:0;;;:::i;31941:173::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;31941:173:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;31941:173:0;-1:-1:-1;;;;;31941:173:0;;:::i;33309:155::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;33309:155:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;33309:155:0;;;;;;-1:-1:-1;;;;;33309:155:0;;:::i;40314:163::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40314:163:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;40314:163:0;;;;;;;;:::i;17662:27::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;17662:27:0;;;:::i;30959:266::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30959:266:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30959:266:0;-1:-1:-1;;;;;30959:266:0;;:::i;37848:268::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37848:268:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;37848:268:0;;;;;;;;;;:::i;21223:500::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;21223:500:0;;;:::i;33622:200::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;33622:200:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;33622:200:0;-1:-1:-1;;;;;33622:200:0;;:::i;69387:382::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;69387:382:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;69387:382:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;69387: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;69387:382:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;69387:382:0;;-1:-1:-1;69387:382:0;;-1:-1:-1;;;;;69387:382:0:i;60239:401::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60239:401:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;60239:401:0;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;60239:401:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;60239: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;60239:401:0;;-1:-1:-1;60239:401:0;-1:-1:-1;60239:401:0;:::i;20961:121::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;20961:121:0;;;:::i;8516:145::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8516:145:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;8516:145:0;-1:-1:-1;;;;;8516:145:0;;:::i;46765:445::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;46765:445:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;46765:445:0;;:::i;73592:93::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;73592:93:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;66351:40;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66351:40:0;;;:::i;38674:173::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38674:173:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;38674:173:0;;;;;;;;;;:::i;9759:109::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9759:109:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9759:109:0;-1:-1:-1;;;;;9759:109:0;;:::i;52071:154::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;52071:154:0;-1:-1:-1;;;;;52071:154:0;;:::i;17992:236::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;17992:236:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;17992:236:0;-1:-1:-1;;;;;17992:236:0;;:::i;40631:241::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40631:241:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;40631:241:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;40631:241:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;40631: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;40631:241:0;;-1:-1:-1;40631:241:0;-1:-1:-1;40631:241:0;;:::i;12092:135::-;-1:-1:-1;;;;;;12186:33:0;;12162:4;12186:33;;;;;;;;;;;;;12092:135;;;;:::o;30062:23::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;30062:23:0;;-1:-1:-1;30062:23:0;:::o;45537:94::-;45617:8;45610:15;;;;;;;;-1:-1:-1;;45610:15:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45585:13;;45610:15;;45617:8;;45610:15;;45617:8;45610:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45537:94;;:::o;38219:138::-;38303:7;38329:22;38342:8;38329:12;:22::i;:::-;38322:29;38219:138;-1:-1:-1;;38219:138:0:o;37249:311::-;20820:7;;-1:-1:-1;;;20820:7:0;;;;20812:35;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;;;;37387:8;36862:32;36873:8;36883:10;36862;:32::i;:::-;:78;;;;36907:33;36919:8;36929:10;36907:11;:33::i;:::-;36862:138;;;;36953:47;36970:17;36978:8;36970:7;:17::i;:::-;36989:10;36953:16;:47::i;:::-;36846:192;;;;;-1:-1:-1;;;36846:192:0;;;;;;;;;;;;-1:-1:-1;;;36846:192:0;;;;;;;;;;;;;;;37415:10;-1:-1:-1;;;;;37415:23:0;;;;37407:48;;;;;-1:-1:-1;;;37407:48:0;;;;;;;;;;;;-1:-1:-1;;;37407:48:0;;;;;;;;;;;;;;;37464:18;;;;:8;:18;;;;;:30;;-1:-1:-1;;;;;;37464:30:0;-1:-1:-1;;;;;37464:30:0;;;;;;;;:18;;37515:17;37464:18;37515:7;:17::i;:::-;-1:-1:-1;;;;;37506:48:0;;;;;;;;;;;20854:1;37249:311;;:::o;28391:199::-;26348:7;:5;:7::i;:::-;-1:-1:-1;;;;;26334:21:0;:10;-1:-1:-1;;;;;26334:21:0;;:50;;;-1:-1:-1;26373:11:0;;-1:-1:-1;;;;;26373:11:0;26359:10;:25;26334:50;26318:114;;;;;-1:-1:-1;;;26318:114:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;28505:26:0;;28497:54;;;;;-1:-1:-1;;;28497:54:0;;;;;;;;;;;;-1:-1:-1;;;28497:54:0;;;;;;;;;;;;;;;28558:11;:26;;-1:-1:-1;;;;;;28558:26:0;-1:-1:-1;;;;;28558:26:0;;;;;;;;;;28391:199::o;59330:41::-;;;;:::o;59287:38::-;;;;:::o;25420:29::-;;;-1:-1:-1;;;;;25420:29:0;;:::o;32352:879::-;32477:6;:13;32441:16;;32469:49;;;;;-1:-1:-1;;;32469:49:0;;;;;;;;;;;;-1:-1:-1;;;32469:49:0;;;;;;;;;;;;;;;32656:6;:13;32541:9;;32576:16;;;;32525:13;;32631:22;;;:38;32627:202;;;-1:-1:-1;32697:6:0;:13;32730:27;;;;-1:-1:-1;32627:202:0;;;-1:-1:-1;32798:22:0;;;32627:202;32915:29;32961:8;32947:23;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;32947:23:0;-1:-1:-1;32915:55:0;-1:-1:-1;32977:14:0;33088:11;33074:124;33105:14;33101:1;:18;33074:124;;;33161:6;33168:1;33161:9;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;33161:9:0;33135:12;33148:9;33135:23;;;;;;;;-1:-1:-1;;;;;33135:35:0;;;:23;;;;;;;;;;;:35;33179:11;;;;;33121:3;33074:124;;;-1:-1:-1;33213:12:0;;32352:879;-1:-1:-1;;;;;;;32352:879:0:o;25795:20::-;;;;:::o;25637:30::-;;;;:::o;14281:147::-;-1:-1:-1;;;14281:147:0;;;;;;;:::o;28714:104::-;28796:16;;28714:104;:::o;28034:213::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;20820:7;;-1:-1:-1;;;20820:7:0;;;;20812:35;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;;;;28159:8;;;28174:20;;;;28206:35;;;;;;;;;;;;;;;;;;;;;;;;;20854:1;28034:213;:::o;59909:85::-;59960:28;59977:10;59960:16;:28::i;:::-;59909:85::o;66538:1750::-;20820:7;;-1:-1:-1;;;20820:7:0;;;;20812:35;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;;;;66689:5;30438:22;30453:6;30438:14;:22::i;:::-;30422:62;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;;;;66724:8;36862:32;36873:8;36883:10;36862;:32::i;:::-;:78;;;;36907:33;36919:8;36929:10;36907:11;:33::i;:::-;36862:138;;;;36953:47;36970:17;36978:8;36970:7;:17::i;36953:47::-;36846:192;;;;;-1:-1:-1;;;36846:192:0;;;;;;;;;;;;-1:-1:-1;;;36846:192:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;66752:24:0;;66744:52;;;;;-1:-1:-1;;;66744:52:0;;;;;;;;;;;;-1:-1:-1;;;66744:52:0;;;;;;;;;;;;;;;66803:37;66818:21;66833:5;66818:14;:21::i;:::-;66803:14;:37::i;:::-;66849:19;66871:17;66882:5;66871:10;:17::i;:::-;66849:39;;66895:17;66915:22;66926:10;66915;:22::i;:::-;66972:25;;;;67010:13;;66895:42;;-1:-1:-1;66972:25:0;67006:120;;67055:15;;67039:31;;;67079:39;;67092:10;;67079:12;:39::i;:::-;67160:15;67138:18;:37;67134:764;;67441:27;;;;;67413:25;;;:55;67493:15;;67477:31;;67517:34;67530:10;67542:8;67517:12;:34::i;:::-;67134:764;;;67811:37;;;;:79;;67874:15;67853:36;;67811:79;:41;:79;:::i;:::-;67783:25;;;:107;67134:764;67996:15;67966:27;;;:45;68110:1;68092:19;;68157:24;68172:8;68157:14;:24::i;:::-;68267:8;68248:10;-1:-1:-1;;;;;68217:65:0;68234:5;-1:-1:-1;;;;;68217:65:0;;;;;;;;;;;37045:1;;;30491;20854;66538:1750;;;:::o;27405:517::-;26348:7;:5;:7::i;:::-;-1:-1:-1;;;;;26334:21:0;:10;-1:-1:-1;;;;;26334:21:0;;:50;;;-1:-1:-1;26373:11:0;;-1:-1:-1;;;;;26373:11:0;26359:10;:25;26334:50;26318:114;;;;;-1:-1:-1;;;26318:114:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;27494:12;27509:25;27528:4;27509:10;:25::i;:::-;27494:40;-1:-1:-1;27541:11:0;27562:12;;;:33;;;27588:7;27578;:17;27562:33;27559:174;;;27629:1;27619:7;:11;27611:40;;;;;-1:-1:-1;;;27611:40:0;;;;;;;;;;;;-1:-1:-1;;;27611:40:0;;;;;;;;;;;;;;;-1:-1:-1;27669:7:0;27559:174;;;-1:-1:-1;27718:7:0;27559:174;27769:11;;27746:43;;;;;;;;-1:-1:-1;;;;;27769:11:0;;;;27757:10;;27746:43;;;;;;;;;;27896:11;;27886:30;;-1:-1:-1;;;;;27896:11:0;27909:6;27886:9;:30::i;:::-;26439:1;;27405:517;:::o;46290:134::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;46390:28;:12;46405:13;;46390:28;:::i;26075:26::-;;;-1:-1:-1;;;;;26075:26:0;;:::o;60942:491::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;61095:30;61087:55;;;;;-1:-1:-1;;;61087:55:0;;;;;;;;;;;;-1:-1:-1;;;61087:55:0;;;;;;;;;;;;;;;61185:22;;61216:24;;61156:157;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61320:22;:48;;;;61375:24;:52;60942:491::o;25983:28::-;;;;:::o;69844:463::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;69991:28;69983:53;;;;;-1:-1:-1;;;69983:53:0;;;;;;;;;;;;-1:-1:-1;;;69983:53:0;;;;;;;;;;;;;;;70075:20;;70104:22;;70048:147;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;70202:20;:44;;;;70253:22;:48;69844:463::o;20553:19::-;;;-1:-1:-1;;;20553:19:0;;;;;:::o;68641:174::-;68767:42;68784:5;68791:3;68796:8;68767:42;;;;;;;;;;;;:16;:42::i;42204:820::-;42351:33;42396:16;42421:2;42396:28;;42431:16;42456:2;42431:28;;42466:16;42491:2;42466:28;;42501:16;42526:2;42501:28;;42536:18;42607:3;:10;42594:3;:10;42581:3;:10;42568:3;:10;:23;:36;:49;42557:61;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;42557:61:0;87:34:-1;135:17;;-1:-1;42557:61:0;-1:-1:-1;42536:82:0;-1:-1:-1;42536:82:0;42664:6;;42698:69;42714:3;:10;42710:1;:14;42698:69;;;42753:3;42757:1;42753:6;;;;;;;;;;;;;;;;42740:5;42746:3;;;;;;42740:10;;;;;;;;;;;:19;-1:-1:-1;;;;;42740:19:0;;;;;;;;-1:-1:-1;42726:3:0;;42698:69;;;-1:-1:-1;42782:1:0;42773:69;42789:3;:10;42785:1;:14;42773:69;;;42828:3;42832:1;42828:6;;;;;;;;;;;;;;;;42815:5;42821:3;;;;;;42815:10;;;;;;;;;;;:19;-1:-1:-1;;;;;42815:19:0;;;;;;;;-1:-1:-1;42801:3:0;;42773:69;;;-1:-1:-1;42857:1:0;42848:69;42864:3;:10;42860:1;:14;42848:69;;;42903:3;42907:1;42903:6;;;;;;;;;;;;;;;;42890:5;42896:3;;;;;;42890:10;;;;;;;;;;;:19;-1:-1:-1;;;;;42890:19:0;;;;;;;;-1:-1:-1;42876:3:0;;42848:69;;;-1:-1:-1;42932:1:0;42923:69;42939:3;:10;42935:1;:14;42923:69;;;42978:3;42982:1;42978:6;;;;;;;;;;;;;;;;42965:5;42971:3;;;;;;42965:10;;;;;;;;;;;:19;-1:-1:-1;;;;;42965:19:0;;;;;;;;-1:-1:-1;42951:3:0;;42923:69;;;-1:-1:-1;43012:5:0;;42204:820;-1:-1:-1;;;;;;;;;;;42204:820:0:o;59435:47::-;;;;;;;;;;;;;:::o;43030:516::-;43098:27;43220:2;43233:7;43229:40;;-1:-1:-1;;43251:10:0;;;;;;;;;;;;-1:-1:-1;;;43251:10:0;;;;;;43229:40;43284:2;43275:6;43308:53;43315:6;;43308:53;;43332:5;;43351:2;43346:7;;;;43308:53;;;43367:17;43397:3;43387:14;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;43387:14:0;87:34:-1;135:17;;-1:-1;43387:14:0;-1:-1:-1;43367:34:0;-1:-1:-1;;;43417:7:0;;43431:84;43438:6;;43431:84;;43487:2;43483:1;:6;43478:2;:11;43467:24;;43455:4;43460:3;;;;;;;43455:9;;;;;;;;;;;:36;-1:-1:-1;;;;;43455:36:0;;;;;;;;-1:-1:-1;43505:2:0;43500:7;;;;43431:84;;;-1:-1:-1;43535:4:0;43030:516;-1:-1:-1;;;;;43030:516:0:o;61719:163::-;61814:11;61844:32;61869:6;61844:24;:32::i;45313:121::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;45408:20;:8;45419:9;;45408:20;:::i;43552:457::-;43699:42;;;;;;;;;;;-1:-1:-1;;;43699:42:0;;;;43767:13;;43777:2;43767:13;;;43628;43767;;;;;;-1:-1:-1;;;;;43677:14:0;;;43699:42;43628:13;;43767;;;21:6:-1;;104:10;43767:13:0;87:34:-1;135:17;;-1:-1;43767:13:0;43748:32;;-1:-1:-1;;;43787:3:0;43791:1;43787:6;;;;;;;;;;;:12;-1:-1:-1;;;;;43787:12:0;;;;;;;;;-1:-1:-1;;;43806:3:0;43810:1;43806:6;;;;;;;;;;;:12;-1:-1:-1;;;;;43806:12:0;;;;;;;;-1:-1:-1;43830:6:0;43825:154;43846:2;43842:1;:6;43825:154;;;43877:8;43909:1;43892:5;43898:1;43902:2;43898:6;43892:13;;;;;;;;;;-1:-1:-1;;;;;43892:18:0;;;;43886:25;;43877:35;;;;;;;;;;;;;;;;;;43864:3;43870:1;43872;43870:3;43868:1;:5;43864:10;;;;;;;;;;;:48;-1:-1:-1;;;;;43864:48:0;;;;;;;;;43934:8;43949:5;43955:1;43959:2;43955:6;43949:13;;;;;;;43934:37;;43949:13;;;43965:4;43943:27;;43934:37;;;;;;;;;;;;;;43921:3;43927:1;43929;43927:3;43925:1;:5;43921:10;;;;;;;;;;;:50;-1:-1:-1;;;;;43921:50:0;;;;;;;;-1:-1:-1;43850:3:0;;43825:154;;;-1:-1:-1;43999:3:0;43552:457;-1:-1:-1;;;;43552:457:0:o;60786:84::-;60851:10;60835:27;;;;:15;:27;;;;;:29;;;;;;60786:84::o;34217:150::-;34311:7;30605:24;;;:14;:24;;;;;;34287:8;;-1:-1:-1;;;;;30605:24:0;30589:76;;;;;-1:-1:-1;;;30589:76:0;;;;;;;;;;;;-1:-1:-1;;;30589:76:0;;;;;;;;;;;;;;;-1:-1:-1;;34337:24:0;;;;:14;:24;;;;;;-1:-1:-1;;;;;34337:24:0;;34217:150::o;31653:171::-;-1:-1:-1;;;;;31762:18:0;31739:4;31762:18;;;:10;:18;;;;;:38;;;31803:15;-1:-1:-1;;31653:171:0:o;31388:197::-;31471:4;-1:-1:-1;;;;;31495:20:0;;31487:48;;;;;-1:-1:-1;;;31487:48:0;;;;;;;;;;;;-1:-1:-1;;;31487:48:0;;;;;;;;;;;;;;;31549:22;31564:6;31549:14;:22::i;:::-;:30;;31578:1;31549:30;;;31574:1;31549:30;31542:37;;;31388:197;-1:-1:-1;;31388:197:0:o;52435:209::-;20820:7;;-1:-1:-1;;;20820:7:0;;;;20812:35;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;;;;52575:9;30438:22;30453:6;30438:14;:22::i;:::-;30422:62;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;;;;52603:35;52616:10;52628:9;52603:12;:35::i;9442:140::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;9525:6;;9504:40;;9541:1;;-1:-1:-1;;;;;9525:6:0;;9504:40;;9541:1;;9504:40;9555:6;:19;;-1:-1:-1;;;;;;9555:19:0;;;9442:140::o;25889:27::-;;;;:::o;45713:167::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;45812:24;:10;45825:11;;45812:24;:::i;:::-;;45848:26;45862:11;;45848:26;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;;74:27;45848:26:0;;137:4:-1;117:14;;;-1:-1;;113:30;157:16;;;45848:26:0;;;;-1:-1:-1;45848:26:0;;-1:-1:-1;;;;45848:26:0;45713:167;;:::o;41032:257::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;41175:6;41171:113;41187:22;;;41171:113;;;41225:51;41235:11;;41247:1;41235:14;;;;;;;;;;;;;-1:-1:-1;;;;;41235:14:0;41251:21;;41273:1;41251:24;;;;;;;;;;;;;41225:9;:51::i;:::-;41211:3;;41171:113;;;;41032:257;;;;:::o;70572:727::-;70678:4;70656:6;30438:22;30453:6;30438:14;:22::i;:::-;30422:62;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;;;;70694:15;70712:18;70723:6;70712:10;:18::i;:::-;70694:36;;70830:18;70877:15;70851:3;:23;;;:41;70830:62;;70899:8;70934:18;;70917:13;:35;70914:312;;-1:-1:-1;71055:8:0;;70914:312;;;71200:18;;71170:8;;:27;;71183:13;71170:27;:12;:27;:::i;:::-;:48;;;;;;71164:54;;70914:312;71271:22;;71247:20;;71239:29;;:3;;:29;:7;:29;:::i;:::-;:54;;;;;;;70572:727;-1:-1:-1;;;;;;70572:727:0:o;61995:456::-;-1:-1:-1;;;;;62318:26:0;;;;62114:20;62318:26;;;:15;:26;;;;;;;;;;62171:267;;62252:4;62171:267;;;;;;;;;;;;;;;;;;-1:-1:-1;;62171:267:0;;;;;;;26:21:-1;;;22:32;;6:49;;62171:267:0;;;;;;;62153:292;;;;;;61995:456::o;8729:79::-;8794:6;;-1:-1:-1;;;;;8794:6:0;8729:79;:::o;9064:92::-;9142:6;;-1:-1:-1;;;;;9142:6:0;9128:10;:20;;9064:92::o;66310:36::-;;;;:::o;33982:104::-;34067:6;:13;33982:104;:::o;45985:215::-;46069:10;46063:24;46035:13;;46063:24;-1:-1:-1;;46063:24:0;;;;;;;;;;;46060:135;;46110:14;;;;;;;;;-1:-1:-1;;;;;46110:14:0;-1:-1:-1;;;;;46110:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;46110:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;46110:37:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;46110: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;46110: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;46110:37:0;;-1:-1:-1;46103:44:0;;-1:-1:-1;;;;46103:44:0;46060:135;46177:10;46170:17;;;;;;;;;;;;;-1:-1:-1;;46170:17:0;;;;;;;;;;;;;;;;;;;;;;;;;;;46177:10;46170:17;;46177:10;46170:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31941:173;32057:4;32033:8;30438:22;30453:6;30438:14;:22::i;:::-;30422:62;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;32080:20:0;;;;;:10;:20;;;;;:28;;31941:173::o;33309:155::-;33401:4;33424:24;;;:14;:24;;;;;;;-1:-1:-1;;;;;33424:34:0;;;:24;;:34;;33309:155::o;40314:163::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;40428:43;40438:10;40450:20;40428:9;:43::i;:::-;40314:163;;:::o;17662:27::-;;;-1:-1:-1;;;;;17662:27:0;;:::o;30959:266::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;31051:6;30438:22;30453:6;30438:14;:22::i;:::-;30422:62;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;31087:18:0;;31069:15;31087:18;;;:10;:18;;;;;;;;;31138:15;31112:23;;;:41;31207:11;;31197:22;;;;;;;31087:18;;31197:22;;;;;;;;;30491:1;8962;30959:266;:::o;37848:268::-;20820:7;;-1:-1:-1;;;20820:7:0;;;;20812:35;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;37963:17:0;;37970:10;37963:17;;37955:42;;;;;-1:-1:-1;;;37955:42:0;;;;;;;;;;;;-1:-1:-1;;;37955:42:0;;;;;;;;;;;;;;;38028:10;38004:35;;;;:23;:35;;;;;;;;-1:-1:-1;;;;;38004:40:0;;;;;;;;;;;;:52;;-1:-1:-1;;38004:52:0;;;;;;;;;;38068:42;;;;;;;38004:40;;38028:10;38068:42;;;;;;;;;;;37848:268;;:::o;21223:500::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;21293:7;;-1:-1:-1;;;21293:7:0;;;;:16;21285:42;;;;;-1:-1:-1;;;21285:42:0;;;;;;;;;;;;-1:-1:-1;;;21285:42:0;;;;;;;;;;;;;;;21341;;;21357:4;21349:21;21341:42;;;;21372:10;;21341:42;;;;;;;;;;21462:48;21472:10;21484:25;21503:4;21484:10;:25::i;:::-;21462:9;:48::i;:::-;21530:10;21517:24;33622:200;-1:-1:-1;;;;;30232:18:0;;33745:14;30232:18;;;:10;:18;;;;;:38;;;33723:6;;30216:88;;;;;-1:-1:-1;;;30216:88:0;;;;;;;;;;;;-1:-1:-1;;;30216:88:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;33778:18:0;;;;;:10;:18;;;;;:38;;;;33622:200::o;69387:382::-;20820:7;;-1:-1:-1;;;20820:7:0;;;;20812:35;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;;;;69571:8;36862:32;36873:8;36883:10;36862;:32::i;:::-;:78;;;;36907:33;36919:8;36929:10;36907:11;:33::i;:::-;36862:138;;;;36953:47;36970:17;36978:8;36970:7;:17::i;36953:47::-;36846:192;;;;;-1:-1:-1;;;36846:192:0;;;;;;;;;;;;-1:-1:-1;;;36846:192:0;;;;;;;;;;;;;;;69598:17;69606:8;69598:7;:17::i;:::-;30438:22;30453:6;30438:14;:22::i;:::-;30422:62;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;;;;69627:34;69640:5;69647:3;69652:8;69627:12;:34::i;:::-;69676:51;69699:5;69706:3;69711:8;69721:5;69676:22;:51::i;:::-;69668:93;;;;;-1:-1:-1;;;69668:93:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;37045:1;20854;69387:382;;;;:::o;60239:401::-;60526:9;-1:-1:-1;;;;;60363:172:0;:159;60387:105;60428:53;60459:9;60470:10;60428:30;:53::i;:::-;60387:28;:105::i;:::-;60503:10;;60363:159;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;60363:13:0;;-1:-1:-1;;;60363:159:0:i;:::-;-1:-1:-1;;;;;60363:172:0;;60347:216;;;;;-1:-1:-1;;;60347:216:0;;;;;;;;;;;;-1:-1:-1;;;60347:216:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;60572:26:0;;;;;;:15;:26;;;;;:28;;;;;;60607:27;60588:9;60607:16;:27::i;20961:121::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;20820:7;;-1:-1:-1;;;20820:7:0;;;;20812:35;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;;;;21045:9;;;;;;;21061:7;:15;;-1:-1:-1;;;;21061:15:0;;;20961:121::o;8516: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;;;;;;;7076:13;7096:83;;;;7140:4;7125:19;;-1:-1:-1;;;;7125:19:0;;;;;7153:18;;;;;7096:83;8582:6;:15;;-1:-1:-1;;;;;;8582:15:0;-1:-1:-1;;;;;8582:15:0;;;;;;;;;;;8613:40;;8646:6;;;-1:-1:-1;;8613:40:0;;-1:-1:-1;;8613:40:0;7201:14;7197:57;;;7226:12;:20;;-1:-1:-1;;7226:20:0;;;8516:145;;:::o;46765:445::-;30641:1;30605:24;;;:14;:24;;;;;;46864:13;;46841:8;;-1:-1:-1;;;;;30605:24:0;30589:76;;;;;-1:-1:-1;;;30589:76:0;;;;;;;;;;;;-1:-1:-1;;;30589:76:0;;;;;;;;;;;;;;;46922:12;46916:26;46889:17;;46916:26;-1:-1:-1;;46916:26:0;;;;;;;;;;;46913:138;;46964:14;;;;;;;;;-1:-1:-1;;;;;46964:14:0;-1:-1:-1;;;;;46964:36:0;;:38;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;46964:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;46964:38:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;46964: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;46964: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;46964:38:0;;-1:-1:-1;46913:138:0;;-1:-1:-1;;;;46913:138:0;;47031:12;47025:18;;;;;;;;;;;;;-1:-1:-1;;47025:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;47031:12;47025:18;;47031:12;47025:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46913:138;47066;47096:3;47108:38;47140:4;47108:23;:38::i;:::-;47066:138;;;;;;;;;;;;;-1:-1:-1;;;47066:138:0;;;47167:30;47188:8;47167:20;:30::i;:::-;47066:21;:138::i;73592:93::-;73678:1;73592:93;:::o;66351:40::-;;;;:::o;38674:173::-;-1:-1:-1;;;;;38799:31:0;;;38776:4;38799:31;;;:23;:31;;;;;;;;:42;;;;;;;;;;;;;;;38674:173::o;9759:109::-;8941:9;:7;:9::i;:::-;8933:18;;;;;;9832:28;9851:8;9832:18;:28::i;:::-;9759:109;:::o;52071:154::-;20820:7;;-1:-1:-1;;;20820:7:0;;;;20812:35;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;-1:-1:-1;;;20812:35:0;;;;;;;;;;;;;;;52183:36;52196:10;52216:1;52183:12;:36::i;17992:236::-;18085:12;;18066:4;;-1:-1:-1;;;;;18085:12:0;18082:141;;-1:-1:-1;;;;;;18129:16:0;;;18122:23;;18082:141;18182:12;;18175:40;;;-1:-1:-1;;;18175:40:0;;-1:-1:-1;;;;;18175:40:0;;;;;;;;;18182:12;;;;;18175:30;;:40;;;;;;;;;;;;;;18182:12;18175:40;;;5:2:-1;;;;30:1;27;20:12;5:2;18175:40:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;18175:40:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;18175:40:0;;-1:-1:-1;18168:47:0;;40631:241;8941:9;:7;:9::i;:::-;8933:18;;;;;;40762:6;40758:109;40774:22;;;40758:109;;;40812:47;40822:11;;40834:1;40822:14;;;;;;;;;;;;;-1:-1:-1;;;;;40822:14:0;40838:20;40812:9;:47::i;:::-;40798:3;;40758:109;;;;40631:241;;;:::o;39264:251::-;39349:7;39396:18;;;:8;:18;;;;;;-1:-1:-1;;;;;39396:18:0;39429:31;39421:57;;;;;-1:-1:-1;;;39421:57:0;;;;;;;;;;;;-1:-1:-1;;;39421:57:0;;;;;;;;;;;;;;38940:150;39034:4;39057:18;;;:8;:18;;;;;;;-1:-1:-1;;;;;39057:27:0;;;:18;;:27;;38940:150::o;62561:594::-;62635:15;62653:21;62664:9;62653:10;:21::i;:::-;62635:39;;62683:11;62697:35;62722:9;62697:24;:35::i;:::-;62756:11;;62746:53;;;;;;;;62683:49;;-1:-1:-1;62780:10:0;;-1:-1:-1;;;;;62746:53:0;;;62756:11;62746:53;;;;;;;;;;62998:15;62972:23;;;:41;63026:10;;63022:128;;63113:29;63123:10;63135:6;63113:9;:29::i;18535:684::-;18604:10;;18601:613;;18628:12;;-1:-1:-1;;;;;18628:12:0;18625:582;;18688:6;18675:9;:19;;18667:48;;;;;-1:-1:-1;;;18667:48:0;;;;;;;;;;;;-1:-1:-1;;;18667:48:0;;;;;;;;;;;;;;;18625:582;;;18764:12;;18809:30;;;-1:-1:-1;;;18809:30:0;;18833:4;18809:30;;;;;;-1:-1:-1;;;;;18764:12:0;;;;18742;;18764;;18809:15;;:30;;;;;;;;;;;;;;;18764:12;18809:30;;;5:2:-1;;;;30:1;27;20:12;5:2;18809:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;18809:30:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;18809:30:0;18850:53;;;-1:-1:-1;;;18850:53:0;;18869:10;18850:53;;;;18889:4;18850:53;;;;;;;;;;;;18809:30;;-1:-1:-1;;;;;;18850:18:0;;;;;:53;;;;;18809:30;;18850:53;;;;;;;;-1:-1:-1;18850:18:0;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;18850:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;18850:53:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;19131:30:0;;;-1:-1:-1;;;19131:30:0;;19155:4;19131:30;;;;;;19164:13;;-1:-1:-1;;;;;19131:15:0;;;;;:30;;;;;18850:53;;19131:30;;;;;;;;:15;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;19131:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;19131:30:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;19131:30:0;:46;19123:74;;;;;-1:-1:-1;;;19123:74:0;;;;;;;;;;;;-1:-1:-1;;;19123:74:0;;;;;;;;;;;;;;35332:128;-1:-1:-1;;;;;35436:18:0;35406:11;35436:18;;;:10;:18;;;;;;35332:128::o;34954:308::-;35045:24;;;;:14;:24;;;;;;-1:-1:-1;;;;;35045:34:0;;;:24;;:34;35041:216;;35141:6;27:10:-1;;39:1;23:18;;45:23;;;35141:19:0;;;;-1:-1:-1;;;;;35141:19:0;;-1:-1:-1;;;;;;35141:19:0;;;;;;;;-1:-1:-1;35216:24:0;;;:14;35141:19;35216:24;;;;:33;;;;;;;;;;34954:308;;:::o;48698:181::-;48756:7;48788:5;;;48812:6;;;;48804:46;;;;;-1:-1:-1;;;48804:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;48870:1;48698:181;-1:-1:-1;;;48698:181:0:o;39665:162::-;39770:1;39740:18;;;:8;:18;;;;;;-1:-1:-1;;;;;39740:18:0;:32;39736:86;;39812:1;39783:18;;;:8;:18;;;;;:31;;-1:-1:-1;;;;;;39783:31:0;;;39665:162::o;19377:645::-;19460:11;;19457:560;;19485:12;;-1:-1:-1;;;;;19485:12:0;19482:528;;19524:39;;-1:-1:-1;;;;;19524:30:0;;;:39;;;;;19555:7;;19524:39;;;;19555:7;19524:30;:39;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;19524:39:0;19482:528;;;19612:12;;19657:20;;;-1:-1:-1;;;19657:20:0;;-1:-1:-1;;;;;19657:20:0;;;;;;;;;19612:12;;;;;19590;;19612;;19657:15;;:20;;;;;;;;;;;;;;19612:12;19657:20;;;5:2:-1;;;;30:1;27;20:12;5:2;19657:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;19657:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;19657:20:0;19688:28;;;-1:-1:-1;;;19688:28:0;;-1:-1:-1;;;;;19688:28:0;;;;;;;;;;;;;;;19657:20;;-1:-1:-1;19688:14:0;;;;;;:28;;;;;19657:20;;19688:28;;;;;;;;-1:-1:-1;19688:14:0;:28;;;5:2:-1;;;;30:1;27;20:12;5:2;19688:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;19688:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;19944:20:0;;;-1:-1:-1;;;19944:20:0;;-1:-1:-1;;;;;19944:20:0;;;;;;;;;19967:13;;19944:15;;;;;:20;;;;;19688:28;;19944:20;;;;;;;:15;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;19944:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;19944:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;19944:20:0;:36;19936:64;;;;;-1:-1:-1;;;19936:64:0;;;;;;;;;;;;-1:-1:-1;;;19936:64:0;;;;;;;;;;;;;;63357:845;63474:11;63452:6;30438:22;30453:6;30438:14;:22::i;:::-;30422:62;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;-1:-1:-1;;;30422:62:0;;;;;;;;;;;;;;;63497:15;63515:18;63526:6;63515:10;:18::i;:::-;63497:36;;63633:18;63680:15;63654:3;:23;;;:41;63633:62;;63722:18;;63705:13;:35;63702:232;;63760:8;;63751:17;;63702:232;;;63908:18;;63878:8;;:27;;63891:13;63878:27;:12;:27;:::i;:::-;:48;;;;;;63869:57;;63702:232;63940:12;63994:24;;63955:36;63968:22;;63955:8;;:12;;:36;;;;:::i;:::-;:63;;;;;;63940:78;;64038:7;64029:6;:16;64025:172;;;64149:7;64139:17;;;;64025:172;;;64188:1;64179:10;;64025:172;30491:1;;;63357:845;;;;:::o;53160:1928::-;26220:16;;26202:15;;:34;26194:60;;;;;-1:-1:-1;;;26194:60:0;;;;;;;;;;;;-1:-1:-1;;;26194:60:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;53328:24:0;;53320:52;;;;;-1:-1:-1;;;53320:52:0;;;;;;;;;;;;-1:-1:-1;;;53320:52:0;;;;;;;;;;;;;;;53521:8;;53557:14;;:72;;;-1:-1:-1;;;53557:72:0;;-1:-1:-1;;;;;53557:72:0;;;;;;;;;;;;;;;53459:13;;;;53521:8;;53557:14;;;:42;;:72;;;;;;;;;;;;:14;:72;;;5:2:-1;;;;30:1;27;20:12;5:2;53557:72:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;53557:72:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;53557:72:0;;;;;;;;;-1:-1:-1;53557:72:0;-1:-1:-1;53652:16:0;53679:27;;;53675:239;;;-1:-1:-1;53728:1:0;53675:239;;;-1:-1:-1;53879:27:0;;;53675:239;53945:17;53965:22;53976:10;53965;:22::i;:::-;54000:13;;53945:42;;-1:-1:-1;53996:186:0;;54102:24;54120:5;54102:17;:24::i;:::-;54135:39;54148:10;54160:5;:13;;;54135:12;:39::i;:::-;54223:15;54194:5;:25;;;:44;54190:427;;54370:18;;54340:25;;;;:49;;;:29;:49;:::i;:::-;54312:25;;;:77;54190:427;;;54591:18;;54573:15;:36;54545:25;;;:64;54190:427;54629:12;;54625:90;;54652:14;;:55;;;-1:-1:-1;;;54652:55:0;;;;;;;;;;;;;;;;-1:-1:-1;;;;;54652:14:0;;;;:37;;:55;;;;;:14;;:55;;;;;;;;:14;;:55;;;5:2:-1;;;;30:1;27;20:12;5:2;54652:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;54652:55:0;;;;54625:90;54723:14;;:53;;;-1:-1:-1;;;54723:53:0;;;;;;;;-1:-1:-1;;;;;54723:53:0;;;;;;;;;:14;;;;;:32;;:53;;;;;:14;;:53;;;;;;;:14;;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;54723:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;54890:16:0;;54812:101;;54890:16;;-1:-1:-1;;;;;;54812:101:0;;;-1:-1:-1;54837:1:0;;54812:101;;54837:1;;54812:101;55058:24;55073:8;55058:14;:24::i;:::-;26261:1;;;;;53160:1928;;:::o;41344:560::-;-1:-1:-1;;;;;41451:24:0;;41443:52;;;;;-1:-1:-1;;;41443:52:0;;;;;;;;;;;;-1:-1:-1;;;41443:52:0;;;;;;;;;;;;;;;41504:17;41524:22;41535:10;41524;:22::i;:::-;41504:42;;41584:5;:25;;;41561:20;:48;41553:77;;;;;-1:-1:-1;;;41553:77:0;;;;;;;;;;;;-1:-1:-1;;;41553:77:0;;;;;;;;;;;;;;;41639:24;41657:5;41639:17;:24::i;:::-;41670:39;41683:10;41695:5;:13;;;41670:12;:39::i;:::-;41716:25;;;:48;;;41878:13;;41800:98;;-1:-1:-1;;;;;41800:98:0;;;41878:13;;41800:98;;41878:13;;41800:98;41344:560;;;:::o;49589:470::-;49647:7;49891:6;49887:47;;-1:-1:-1;49921:1:0;49914:8;;49887:47;49958:5;;;49962:1;49958;:5;:1;49982:5;;;;;:10;49974:56;;;;-1:-1:-1;;;49974:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71813:362;71961:4;71982:15;:2;-1:-1:-1;;;;;71982:13:0;;:15::i;:::-;71977:50;;-1:-1:-1;72015:4:0;72008:11;;71977:50;72049:78;;-1:-1:-1;;;72049:78:0;;72094:10;72049:78;;;;;;-1:-1:-1;;;;;72049:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;72033:13;;72049:36;;;;;;72094:10;;72106:4;;72112:7;;72121:5;;72049:78;;;;;;;;;;;72033: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;72049:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;72049:78:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;72049:78:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;72049:78:0;-1:-1:-1;;;;;;72142:26:0;-1:-1:-1;;;72142:26:0;;-1:-1:-1;;71813:362:0;;;;;;:::o;58624:269::-;58826:58;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;58826:58:0;;;;;;;58816:69;;;;;;58624:269::o;56418:1930::-;56496:7;56559:9;:16;56579:2;56559:22;56555:74;;-1:-1:-1;56614:1:0;56598:19;;56555:74;56990:4;56975:20;;56969:27;57036:4;57021:20;;57015:27;57090:4;57075:20;;57069:27;56698:9;57061:36;58020:66;58007:79;;58003:129;;;58118:1;58103:17;;;;;;;58003:129;58148:1;:7;;58153:2;58148:7;;:18;;;;;58159:1;:7;;58164:2;58159:7;;58148:18;58144:68;;;58198:1;58183:17;;;;;;;58144:68;58316:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;58316:24:0;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;58316:24:0;;-1:-1:-1;;58316:24:0;;;56418:1930;-1:-1:-1;;;;;;;56418:1930:0:o;7348:476::-;7788:7;7776:20;7811:7;7348:476;:::o;10018:187::-;-1:-1:-1;;;;;10092:22:0;;10084:31;;;;;;10152:6;;10131:38;;-1:-1:-1;;;;;10131:38:0;;;;10152:6;;10131:38;;10152:6;;10131:38;10180:6;:17;;-1:-1:-1;;;;;;10180:17:0;-1:-1:-1;;;;;10180:17:0;;;;;;;;;;10018:187::o;34495:396::-;34573:12;;34569:317;;34734:16;:18;;;;;;;;34847:31;;34495:396::o;64829:422::-;65196:20;65235:8;;;64829:422::o;72624:1064::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;72624:1064:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;72624:1064:0;;;-1:-1:-1;72624:1064:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;

Swarm Source

bzzr://47f15e51181351647a87d6980e0f8f20a1f88485a060e1fd9ce02eb8828eb7b4
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.