Token FDC 1 Week

 

Overview [ERC-721]

Max Total Supply:
130 KEY

Holders:
105

Transfers:
-

Loading
[ Download CSV Export  ] 
Loading
[ Download CSV Export  ] 
Loading

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

Similar Match Source Code
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0x75fa3aa7e999b9899010c5f05e52cd0543dab465

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 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

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.