Contract Overview
Balance:
0 Ether
More Info
My Name Tag:
Not Available
TokenTracker:
Txn Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x1071a3c366f7186072dae31b9e34dec52d25d3e5f091093be329ff8a977bd9b3 | Purchase For | 4520502 | 1077 days 14 hrs ago | 0xdd8e2548da5a992a63ae5520c6bc92c37a2bcc44 | IN | 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c | 0 Ether | 0.000151182 | |
0x65883974acb87f5186d9a602af13cffd2eec1a70d1a9eb478ac4c0c26c5f52ad | Purchase For | 4463248 | 1087 days 13 hrs ago | 0xe7de59378f3496a5434bbe998c28b71a72888f18 | IN | 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c | 0 Ether | 0.000137125 | |
0x383cacf5b117935fcbf1291ef15f425e6a2bf06c55973a8c86f17799c28b67af | Purchase For | 4462701 | 1087 days 15 hrs ago | 0x3ca206264762caf81a8f0a843bbb850987b41e16 | IN | 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c | 0 Ether | 0.000137125 | |
0xf68c3129b16ad5b6ac53893d3b814813e11a3c3642d06b3cc92d01333488f95c | Purchase For | 4462691 | 1087 days 15 hrs ago | 0xdd8e2548da5a992a63ae5520c6bc92c37a2bcc44 | IN | 0x677f09a88b3a1fdccfddab6e6cfd63dd02cbfa7c | 0 Ether | 0.000167125 |
[ Download CSV Export ]
Latest 9 internal transactions
[ Download CSV Export ]
Contract Name:
PublicLock
Compiler Version
v0.5.7+commit.6da8b019
Optimization Enabled:
Yes with 200 runs
Other Settings:
petersburg EvmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2019-05-28 */ // File: contracts/interfaces/IERC721.sol pragma solidity 0.5.7; /// @title ERC-721 Non-Fungible Token Standard /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// Note: the ERC-165 identifier for this interface is 0x80ac58cd interface IERC721 { /// @dev This emits when ownership of any NFT changes by any mechanism. /// This event emits when NFTs are created (`from` == 0) and destroyed /// (`to` == 0). Exception: during contract creation, any number of NFTs /// may be created and assigned without emitting Transfer. At the time of /// any transfer, the approved address for that NFT (if any) is reset to none. event Transfer(address indexed _from, address indexed _to, uint indexed _tokenId); /// @dev This emits when the approved address for an NFT is changed or /// reaffirmed. The zero address indicates there is no approved address. /// When a Transfer event emits, this also indicates that the approved /// address for that NFT (if any) is reset to none. event Approval(address indexed _owner, address indexed _approved, uint indexed _tokenId); /// @dev This emits when an operator is enabled or disabled for an owner. /// The operator can manage all NFTs of the owner. event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE /// THEY MAY BE PERMANENTLY LOST /// @dev Throws unless `msg.sender` is the current owner, an authorized /// operator, or the approved address for this NFT. Throws if `_from` is /// not the current owner. Throws if `_to` is the zero address. Throws if /// `_tokenId` is not a valid NFT. /// @param _from The current owner of the NFT /// @param _to The new owner /// @param _tokenId The NFT to transfer function transferFrom(address _from, address _to, uint _tokenId) external payable; /// @notice Set or reaffirm the approved address for an NFT /// @dev The zero address indicates there is no approved address. /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized /// operator of the current owner. /// @param _approved The new approved NFT controller /// @param _tokenId The NFT to approve function approve(address _approved, uint _tokenId) external payable; /// @notice Transfers the ownership of an NFT from one address to another address /// @dev Throws unless `msg.sender` is the current owner, an authorized /// operator, or the approved address for this NFT. Throws if `_from` is /// not the current owner. Throws if `_to` is the zero address. Throws if /// `_tokenId` is not a valid NFT. When transfer is complete, this function /// checks if `_to` is a smart contract (code size > 0). If so, it calls /// `onERC721Received` on `_to` and throws if the return value is not /// `bytes4(keccak256('onERC721Received(address,address,uint,bytes)'))`. /// @param _from The current owner of the NFT /// @param _to The new owner /// @param _tokenId The NFT to transfer /// @param data Additional data with no specified format, sent in call to `_to` function safeTransferFrom(address _from, address _to, uint _tokenId, bytes calldata data) external payable; /// @notice Transfers the ownership of an NFT from one address to another address /// @dev This works identically to the other function with an extra data parameter, /// except this function just sets data to '' /// @param _from The current owner of the NFT /// @param _to The new owner /// @param _tokenId The NFT to transfer function safeTransferFrom(address _from, address _to, uint _tokenId) external payable; /// @notice Enable or disable approval for a third party ('operator') to manage /// all of `msg.sender`'s assets. /// @dev Emits the ApprovalForAll event. The contract MUST allow /// multiple operators per owner. /// @param _operator Address to add to the set of authorized operators. /// @param _approved True if the operator is approved, false to revoke approval function setApprovalForAll(address _operator, bool _approved) external; /// @notice Count all NFTs assigned to an owner /// @dev NFTs assigned to the zero address are considered invalid, and this /// function throws for queries about the zero address. /// @param _owner An address for whom to query the balance /// @return The number of NFTs owned by `_owner`, possibly zero function balanceOf(address _owner) external view returns (uint); /// @notice Find the owner of an NFT /// @dev NFTs assigned to zero address are considered invalid, and queries /// about them do throw. /// @param _tokenId The identifier for an NFT /// @return The address of the owner of the NFT function ownerOf(uint _tokenId) external view returns (address); /// @notice Get the approved address for a single NFT /// @dev Throws if `_tokenId` is not a valid NFT /// @param _tokenId The NFT to find the approved address for /// @return The approved address for this NFT, or the zero address if there is none function getApproved(uint _tokenId) external view returns (address); /// @notice Query if an address is an authorized operator for another address /// @param _owner The address that owns the NFTs /// @param _operator The address that acts on behalf of the owner /// @return True if `_operator` is an approved operator for `_owner`, false otherwise function isApprovedForAll(address _owner, address _operator) external view returns (bool); /// @notice A descriptive name for a collection of NFTs in this contract function name() external view returns (string memory _name); } // File: zos-lib/contracts/Initializable.sol pragma solidity >=0.4.24 <0.6.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool wasInitializing = initializing; initializing = true; initialized = true; _; initializing = wasInitializing; } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. uint256 cs; assembly { cs := extcodesize(address) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } // File: openzeppelin-eth/contracts/ownership/Ownable.sol pragma solidity ^0.5.0; /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable is Initializable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function initialize(address sender) public initializer { _owner = sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * @notice Renouncing to ownership will leave the contract without an owner. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[50] private ______gap; } // File: openzeppelin-solidity/contracts/introspection/IERC165.sol pragma solidity ^0.5.2; /** * @title IERC165 * @dev https://eips.ethereum.org/EIPS/eip-165 */ interface IERC165 { /** * @notice Query if a contract implements an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @dev Interface identification is specified in ERC-165. This function * uses less than 30,000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // File: openzeppelin-solidity/contracts/introspection/ERC165.sol pragma solidity ^0.5.2; /** * @title ERC165 * @author Matt Condon (@shrugs) * @dev Implements ERC165 using a lookup table. */ contract ERC165 is IERC165 { bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /* * 0x01ffc9a7 === * bytes4(keccak256('supportsInterface(bytes4)')) */ /** * @dev a mapping of interface id to whether or not it's supported */ mapping(bytes4 => bool) private _supportedInterfaces; /** * @dev A contract implementing SupportsInterfaceWithLookup * implement ERC165 itself */ constructor () internal { _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev implement supportsInterface(bytes4) using a lookup table */ function supportsInterface(bytes4 interfaceId) external view returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev internal method for registering an interface */ function _registerInterface(bytes4 interfaceId) internal { require(interfaceId != 0xffffffff); _supportedInterfaces[interfaceId] = true; } } // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol pragma solidity ^0.5.2; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ contract IERC721Receiver { /** * @notice Handle the receipt of an NFT * @dev The ERC721 smart contract calls this function on the recipient * after a `safeTransfer`. This function MUST return the function selector, * otherwise the caller will revert the transaction. The selector to be * returned can be obtained as `this.onERC721Received.selector`. This * function MAY throw to revert and reject the transfer. * Note: the ERC721 contract address is always the message sender. * @param operator The address which called `safeTransferFrom` function * @param from The address which previously owned the token * @param tokenId The NFT identifier which is being transferred * @param data Additional data with no specified format * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4); } // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Holder.sol pragma solidity ^0.5.2; contract ERC721Holder is IERC721Receiver { function onERC721Received(address, address, uint256, bytes memory) public returns (bytes4) { return this.onERC721Received.selector; } } // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.2; /** * @title ERC20 interface * @dev see https://eips.ethereum.org/EIPS/eip-20 */ interface IERC20 { function transfer(address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); function totalSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } // File: contracts/mixins/MixinFunds.sol pragma solidity 0.5.7; /** * @title An implementation of the money related functions. * @author HardlyDifficult (unlock-protocol.com) */ contract MixinFunds { /** * The token-type that this Lock is priced in. If 0, then use ETH, else this is * a ERC20 token address. */ address public tokenAddress; constructor( address _tokenAddress ) public { require( _tokenAddress == address(0) || IERC20(_tokenAddress).totalSupply() > 0, 'INVALID_TOKEN' ); tokenAddress = _tokenAddress; } /** * Ensures that the msg.sender has paid at least the price stated. * * With ETH, this means the function originally called was `payable` and the * transaction included at least the amount requested. * * Security: be wary of re-entrancy when calling this function. */ function _chargeAtLeast( uint _price ) internal { if(_price > 0) { if(tokenAddress == address(0)) { require(msg.value >= _price, 'NOT_ENOUGH_FUNDS'); } else { IERC20 token = IERC20(tokenAddress); uint balanceBefore = token.balanceOf(address(this)); token.transferFrom(msg.sender, address(this), _price); // There are known bugs in popular ERC20 implements which means we cannot // trust the return value of `transferFrom`. This require statement ensures // that a transfer occurred. require(token.balanceOf(address(this)) > balanceBefore, 'TRANSFER_FAILED'); } } } /** * Transfers funds from the contract to the account provided. * * Security: be wary of re-entrancy when calling this function. */ function _transfer( address _to, uint _amount ) internal { if(_amount > 0) { if(tokenAddress == address(0)) { address(uint160(_to)).transfer(_amount); } else { IERC20 token = IERC20(tokenAddress); uint balanceBefore = token.balanceOf(_to); token.transfer(_to, _amount); // There are known bugs in popular ERC20 implements which means we cannot // trust the return value of `transferFrom`. This require statement ensures // that a transfer occurred. require(token.balanceOf(_to) > balanceBefore, 'TRANSFER_FAILED'); } } } /** * Gets the current balance of the account provided. */ function _getBalance( address _account ) internal view returns (uint) { if(tokenAddress == address(0)) { return _account.balance; } else { return IERC20(tokenAddress).balanceOf(_account); } } } // File: contracts/mixins/MixinDisableAndDestroy.sol pragma solidity 0.5.7; /** * @title Mixin allowing the Lock owner to disable a Lock (preventing new purchases) * and then destroy it. * @author HardlyDifficult * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinDisableAndDestroy is IERC721, Ownable, MixinFunds { // Used to disable payable functions when deprecating an old lock bool public isAlive; event Destroy( uint balance, address indexed owner ); event Disable(); constructor( ) internal { isAlive = true; } // Only allow usage when contract is Alive modifier onlyIfAlive() { require(isAlive, 'LOCK_DEPRECATED'); _; } /** * @dev Used to disable lock before migrating keys and/or destroying contract */ function disableLock() external onlyOwner onlyIfAlive { emit Disable(); isAlive = false; } /** * @dev Used to clean up old lock contracts from the blockchain * TODO: add a check to ensure all keys are INVALID! */ function destroyLock() external onlyOwner { require(isAlive == false, 'DISABLE_FIRST'); emit Destroy(address(this).balance, msg.sender); // this will send any ETH or ERC20 held by the lock to the owner _transfer(msg.sender, _getBalance(address(this))); selfdestruct(msg.sender); // Note we don't clean up the `locks` data in Unlock.sol as it should not be necessary // and leaves some data behind ('Unlock.LockBalances') which may be helpful. } } // File: contracts/interfaces/IUnlock.sol pragma solidity 0.5.7; /** * @title The Unlock Interface * @author Nick Furfaro (unlock-protocol.com) **/ interface IUnlock { // Events event NewLock( address indexed lockOwner, address indexed newLockAddress ); event NewTokenURI( string tokenURI ); event NewGlobalTokenSymbol( string tokenSymbol ); // Use initialize instead of a constructor to support proxies (for upgradeability via zos). function initialize(address _owner) external; /** * @dev Create lock * This deploys a lock for a creator. It also keeps track of the deployed lock. * @param _tokenAddress set to the ERC20 token address, or 0 for ETH. */ function createLock( uint _expirationDuration, address _tokenAddress, uint _keyPrice, uint _maxNumberOfKeys, string calldata _lockName ) external; /** * This function keeps track of the added GDP, as well as grants of discount tokens * to the referrer, if applicable. * The number of discount tokens granted is based on the value of the referal, * the current growth rate and the lock's discount token distribution rate * This function is invoked by a previously deployed lock only. */ function recordKeyPurchase( uint _value, address _referrer // solhint-disable-line no-unused-vars ) external; /** * This function will keep track of consumed discounts by a given user. * It will also grant discount tokens to the creator who is granting the discount based on the * amount of discount and compensation rate. * This function is invoked by a previously deployed lock only. */ function recordConsumedDiscount( uint _discount, uint _tokens // solhint-disable-line no-unused-vars ) external; /** * This function returns the discount available for a user, when purchasing a * a key from a lock. * This does not modify the state. It returns both the discount and the number of tokens * consumed to grant that discount. */ function computeAvailableDiscountFor( address _purchaser, // solhint-disable-line no-unused-vars uint _keyPrice // solhint-disable-line no-unused-vars ) external view returns (uint discount, uint tokens); // Function to read the globalTokenURI field. function getGlobalBaseTokenURI() external view returns (string memory); /** Function to set the globalTokenURI field. * Should throw if called by other than owner */ function setGlobalBaseTokenURI( string calldata _URI ) external; // Function to read the globalTokenSymbol field. function getGlobalTokenSymbol() external view returns (string memory); /** Function to set the globalTokenSymbol field. * Should throw if called by other than owner. */ function setGlobalTokenSymbol( string calldata _symbol ) external; } // File: contracts/mixins/MixinLockCore.sol pragma solidity 0.5.7; /** * @title Mixin for core lock data and functions. * @author HardlyDifficult * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinLockCore is Ownable, MixinFunds, MixinDisableAndDestroy { event PriceChanged( uint oldKeyPrice, uint keyPrice ); event Withdrawal( address indexed _sender, uint _amount ); // Unlock Protocol address // TODO: should we make that private/internal? IUnlock public unlockProtocol; // Duration in seconds for which the keys are valid, after creation // should we take a smaller type use less gas? // TODO: add support for a timestamp instead of duration uint public expirationDuration; // price in wei of the next key // TODO: allow support for a keyPriceCalculator which could set prices dynamically uint public keyPrice; // Max number of keys sold if the keyReleaseMechanism is public uint public maxNumberOfKeys; // A count of how many new key purchases there have been uint public numberOfKeysSold; // Ensure that the Lock has not sold all of its keys. modifier notSoldOut() { require(maxNumberOfKeys > numberOfKeysSold, 'LOCK_SOLD_OUT'); _; } constructor( uint _expirationDuration, uint _keyPrice, uint _maxNumberOfKeys ) internal { require(_expirationDuration <= 100 * 365 * 24 * 60 * 60, 'MAX_EXPIRATION_100_YEARS'); unlockProtocol = IUnlock(msg.sender); // Make sure we link back to Unlock's smart contract. expirationDuration = _expirationDuration; keyPrice = _keyPrice; maxNumberOfKeys = _maxNumberOfKeys; } /** * @dev Called by owner to withdraw all funds from the lock. * TODO: consider allowing anybody to trigger this as long as it goes to owner anyway? */ function withdraw() external onlyOwner { uint balance = _getBalance(address(this)); require(balance > 0, 'NOT_ENOUGH_FUNDS'); // Security: re-entrancy not a risk as this is the last line of an external function _withdraw(balance); } /** * @dev Called by owner to partially withdraw funds from the lock. * TODO: consider allowing anybody to trigger this as long as it goes to owner anyway? */ function partialWithdraw(uint _amount) external onlyOwner { require(_amount > 0, 'GREATER_THAN_ZERO'); uint balance = _getBalance(address(this)); require(balance >= _amount, 'NOT_ENOUGH_FUNDS'); // Security: re-entrancy not a risk as this is the last line of an external function _withdraw(_amount); } /** * A function which lets the owner of the lock to change the price for future purchases. */ function updateKeyPrice( uint _keyPrice ) external onlyOwner onlyIfAlive { uint oldKeyPrice = keyPrice; keyPrice = _keyPrice; emit PriceChanged(oldKeyPrice, keyPrice); } /** * Public function which returns the total number of unique keys sold (both * expired and valid) */ function totalSupply() public view returns (uint) { return numberOfKeysSold; } /** * @dev private version of the withdraw function which handles all withdrawals from the lock. * * Security: Be wary of re-entrancy when calling this. */ function _withdraw(uint _amount) private { _transfer(Ownable.owner(), _amount); emit Withdrawal(msg.sender, _amount); } } // File: contracts/mixins/MixinKeys.sol pragma solidity 0.5.7; /** * @title Mixin for managing `Key` data. * @author HardlyDifficult * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinKeys is Ownable, MixinLockCore { // The struct for a key struct Key { uint tokenId; uint expirationTimestamp; } // Called when the Lock owner expires a user's Key event ExpireKey(uint tokenId); // Keys // Each owner can have at most exactly one key // TODO: could we use public here? (this could be confusing though because it getter will // return 0 values when missing a key) mapping (address => Key) private keyByOwner; // Each tokenId can have at most exactly one owner at a time. // Returns 0 if the token does not exist // TODO: once we decouple tokenId from owner address (incl in js), then we can consider // merging this with numberOfKeysSold into an array instead. mapping (uint => address) private ownerByTokenId; // Addresses of owners are also stored in an array. // Addresses are never removed by design to avoid abuses around referals address[] public owners; // Ensures that an owner owns or has owned a key in the past modifier ownsOrHasOwnedKey( address _owner ) { require( keyByOwner[_owner].expirationTimestamp > 0, 'HAS_NEVER_OWNED_KEY' ); _; } // Ensures that an owner has a valid key modifier hasValidKey( address _owner ) { require( getHasValidKey(_owner), 'KEY_NOT_VALID' ); _; } // Ensures that a key has an owner modifier isKey( uint _tokenId ) { require( ownerByTokenId[_tokenId] != address(0), 'NO_SUCH_KEY' ); _; } // Ensure that the caller owns the key modifier onlyKeyOwner( uint _tokenId ) { require( isKeyOwner(_tokenId, msg.sender), 'ONLY_KEY_OWNER' ); _; } /** * A function which lets the owner of the lock expire a users' key. */ function expireKeyFor( address _owner ) public onlyOwner hasValidKey(_owner) { Key storage key = keyByOwner[_owner]; key.expirationTimestamp = block.timestamp; // Effectively expiring the key emit ExpireKey(key.tokenId); } /** * In the specific case of a Lock, each owner can own only at most 1 key. * @return The number of NFTs owned by `_owner`, either 0 or 1. */ function balanceOf( address _owner ) external view returns (uint) { require(_owner != address(0), 'INVALID_ADDRESS'); return getHasValidKey(_owner) ? 1 : 0; } /** * Checks if the user has a non-expired key. */ function getHasValidKey( address _owner ) public view returns (bool) { return keyByOwner[_owner].expirationTimestamp > block.timestamp; } /** * @notice Find the tokenId for a given user * @return The tokenId of the NFT, else revert */ function getTokenIdFor( address _account ) external view hasValidKey(_account) returns (uint) { return keyByOwner[_account].tokenId; } /** * A function which returns a subset of the keys for this Lock as an array * @param _page the page of key owners requested when faceted by page size * @param _pageSize the number of Key Owners requested per page */ function getOwnersByPage(uint _page, uint _pageSize) public view returns (address[] memory) { require(owners.length > 0, 'NO_OUTSTANDING_KEYS'); uint pageSize = _pageSize; uint _startIndex = _page * pageSize; uint endOfPageIndex; if (_startIndex + pageSize > owners.length) { endOfPageIndex = owners.length; pageSize = owners.length - _startIndex; } else { endOfPageIndex = (_startIndex + pageSize); } // new temp in-memory array to hold pageSize number of requested owners: address[] memory ownersByPage = new address[](pageSize); uint pageIndex = 0; // Build the requested set of owners into a new temporary array: for (uint i = _startIndex; i < endOfPageIndex; i++) { ownersByPage[pageIndex] = owners[i]; pageIndex++; } return ownersByPage; } /** * Checks if the given address owns the given tokenId. */ function isKeyOwner( uint _tokenId, address _owner ) public view returns (bool) { return ownerByTokenId[_tokenId] == _owner; } /** * @dev Returns the key's ExpirationTimestamp field for a given owner. * @param _owner address of the user for whom we search the key */ function keyExpirationTimestampFor( address _owner ) public view ownsOrHasOwnedKey(_owner) returns (uint timestamp) { return keyByOwner[_owner].expirationTimestamp; } /** * Public function which returns the total number of unique owners (both expired * and valid). This may be larger than totalSupply. */ function numberOfOwners() public view returns (uint) { return owners.length; } /** * @notice ERC721: Find the owner of an NFT * @return The address of the owner of the NFT, if applicable */ function ownerOf( uint _tokenId ) public view isKey(_tokenId) returns (address) { return ownerByTokenId[_tokenId]; } /** * Assigns the key a new tokenId (from numberOfKeysSold) if it does not already have * one assigned. */ function _assignNewTokenId( Key storage _key ) internal { if (_key.tokenId == 0) { // This is a brand new owner, else an owner of an expired key buying an extension. // We increment the tokenId counter numberOfKeysSold++; // we assign the incremented `numberOfKeysSold` as the tokenId for the new key _key.tokenId = numberOfKeysSold; } } /** * Records the owner of a given tokenId */ function _recordOwner( address _owner, uint _tokenId ) internal { if (ownerByTokenId[_tokenId] != _owner) { // TODO: this may include duplicate entries owners.push(_owner); // We register the owner of the tokenID ownerByTokenId[_tokenId] = _owner; } } /** * Returns the Key struct for the given owner. */ function _getKeyFor( address _owner ) internal view returns (Key storage) { return keyByOwner[_owner]; } } // File: contracts/mixins/MixinApproval.sol pragma solidity 0.5.7; /** * @title Mixin for the Approval related functions needed to meet the ERC721 * standard. * @author HardlyDifficult * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinApproval is IERC721, MixinDisableAndDestroy, MixinKeys { // Keeping track of approved transfers // This is a mapping of addresses which have approved // the transfer of a key to another address where their key can be transfered // Note: the approver may actually NOT have a key... and there can only // be a single approved beneficiary // Note 2: for transfer, both addresses will be different // Note 3: for sales (new keys on restricted locks), both addresses will be the same mapping (uint => address) private approved; // Keeping track of approved operators for a Key owner. // Since an owner can have up to 1 Key, this is similiar to above // but the approval does not reset when a transfer occurs. mapping (address => mapping (address => bool)) private ownerToOperatorApproved; // Ensure that the caller has a key // or that the caller has been approved // for ownership of that key modifier onlyKeyOwnerOrApproved( uint _tokenId ) { require( isKeyOwner(_tokenId, msg.sender) || _isApproved(_tokenId, msg.sender) || isApprovedForAll(ownerOf(_tokenId), msg.sender), 'ONLY_KEY_OWNER_OR_APPROVED'); _; } /** * This approves _approved to get ownership of _tokenId. * Note: that since this is used for both purchase and transfer approvals * the approved token may not exist. */ function approve( address _approved, uint _tokenId ) external payable onlyIfAlive onlyKeyOwnerOrApproved(_tokenId) { require(msg.sender != _approved, 'APPROVE_SELF'); approved[_tokenId] = _approved; emit Approval(ownerOf(_tokenId), _approved, _tokenId); } /** * @dev Sets or unsets the approval of a given operator * An operator is allowed to transfer all tokens of the sender on their behalf * @param _to operator address to set the approval * @param _approved representing the status of the approval to be set */ function setApprovalForAll( address _to, bool _approved ) external onlyIfAlive { require(_to != msg.sender, 'APPROVE_SELF'); ownerToOperatorApproved[msg.sender][_to] = _approved; emit ApprovalForAll(msg.sender, _to, _approved); } /** * external version * Will return the approved recipient for a key, if any. */ function getApproved( uint _tokenId ) external view returns (address) { return _getApproved(_tokenId); } /** * @dev Tells whether an operator is approved by a given owner * @param _owner owner address which you want to query the approval of * @param _operator operator address which you want to query the approval of * @return bool whether the given operator is approved by the given owner */ function isApprovedForAll( address _owner, address _operator ) public view returns (bool) { return ownerToOperatorApproved[_owner][_operator]; } /** * @dev Checks if the given user is approved to transfer the tokenId. */ function _isApproved( uint _tokenId, address _user ) internal view returns (bool) { return approved[_tokenId] == _user; } /** * Will return the approved recipient for a key transfer or ownership. * Note: this does not check that a corresponding key * actually exists. */ function _getApproved( uint _tokenId ) internal view returns (address) { address approvedRecipient = approved[_tokenId]; require(approvedRecipient != address(0), 'NONE_APPROVED'); return approvedRecipient; } /** * @dev Function to clear current approval of a given token ID * @param _tokenId uint256 ID of the token to be transferred */ function _clearApproval( uint256 _tokenId ) internal { if (approved[_tokenId] != address(0)) { approved[_tokenId] = address(0); } } } // File: contracts/mixins/MixinGrantKeys.sol pragma solidity 0.5.7; /** * @title Mixin allowing the Lock owner to grant / gift keys to users. * @author HardlyDifficult * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinGrantKeys is IERC721, Ownable, MixinKeys { /** * Allows the Lock owner to give a user a key with no charge. */ function grantKey( address _recipient, uint _expirationTimestamp ) external onlyOwner { _grantKey(_recipient, _expirationTimestamp); } /** * Allows the Lock owner to give a collection of users a key with no charge. * All keys granted have the same expiration date. */ function grantKeys( address[] calldata _recipients, uint _expirationTimestamp ) external onlyOwner { for(uint i = 0; i < _recipients.length; i++) { _grantKey(_recipients[i], _expirationTimestamp); } } /** * Allows the Lock owner to give a collection of users a key with no charge. * Each key may be assigned a different expiration date. */ function grantKeys( address[] calldata _recipients, uint[] calldata _expirationTimestamps ) external onlyOwner { for(uint i = 0; i < _recipients.length; i++) { _grantKey(_recipients[i], _expirationTimestamps[i]); } } /** * Give a key to the given user */ function _grantKey( address _recipient, uint _expirationTimestamp ) private { require(_recipient != address(0), 'INVALID_ADDRESS'); Key storage toKey = _getKeyFor(_recipient); require(_expirationTimestamp > toKey.expirationTimestamp, 'ALREADY_OWNS_KEY'); _assignNewTokenId(toKey); _recordOwner(_recipient, toKey.tokenId); toKey.expirationTimestamp = _expirationTimestamp; // trigger event emit Transfer( address(0), // This is a creation. _recipient, toKey.tokenId ); } } // File: contracts/UnlockUtils.sol pragma solidity 0.5.7; // This contract provides some utility methods for use with the unlock protocol smart contracts. // Borrowed from: // https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol#L943 contract UnlockUtils { function strConcat( string memory _a, string memory _b, string memory _c, string memory _d ) public pure returns (string memory _concatenatedString) { bytes memory _ba = bytes(_a); bytes memory _bb = bytes(_b); bytes memory _bc = bytes(_c); bytes memory _bd = bytes(_d); string memory abcd = new string(_ba.length + _bb.length + _bc.length + _bd.length); bytes memory babcd = bytes(abcd); uint k = 0; uint i = 0; for (i = 0; i < _ba.length; i++) { babcd[k++] = _ba[i]; } for (i = 0; i < _bb.length; i++) { babcd[k++] = _bb[i]; } for (i = 0; i < _bc.length; i++) { babcd[k++] = _bc[i]; } for (i = 0; i < _bd.length; i++) { babcd[k++] = _bd[i]; } return string(babcd); } function uint2Str( uint _i ) public pure returns (string memory _uintAsString) { // make a copy of the param to avoid security/no-assign-params error uint c = _i; if (_i == 0) { return '0'; } uint j = _i; uint len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint k = len - 1; while (c != 0) { bstr[k--] = byte(uint8(48 + c % 10)); c /= 10; } return string(bstr); } function address2Str( address _addr ) public pure returns(string memory) { bytes32 value = bytes32(uint256(_addr)); bytes memory alphabet = '0123456789abcdef'; bytes memory str = new bytes(42); str[0] = '0'; str[1] = 'x'; for (uint i = 0; i < 20; i++) { str[2+i*2] = alphabet[uint8(value[i + 12] >> 4)]; str[3+i*2] = alphabet[uint8(value[i + 12] & 0x0f)]; } return string(str); } } // File: contracts/mixins/MixinLockMetadata.sol pragma solidity 0.5.7; /** * @title Mixin for metadata about the Lock. * @author HardlyDifficult * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinLockMetadata is IERC721, ERC165, Ownable, MixinLockCore, UnlockUtils, MixinKeys { /// A descriptive name for a collection of NFTs in this contract.Defaults to "Unlock-Protocol" but is settable by lock owner string private lockName; /// An abbreviated name for NFTs in this contract. Defaults to "KEY" but is settable by lock owner string private lockSymbol; // the base Token URI for this Lock. If not set by lock owner, the global URI stored in Unlock is used. string private baseTokenURI; event NewLockSymbol( string symbol ); constructor( string memory _lockName ) internal { lockName = _lockName; // registering the optional erc721 metadata interface with ERC165.sol using // the ID specified in the standard: https://eips.ethereum.org/EIPS/eip-721 _registerInterface(0x5b5e139f); } /** * Allows the Lock owner to assign a descriptive name for this Lock. */ function updateLockName( string calldata _lockName ) external onlyOwner { lockName = _lockName; } /** * @dev Gets the token name * @return string representing the token name */ function name( ) external view returns (string memory) { return lockName; } /** * Allows the Lock owner to assign a Symbol for this Lock. */ function updateLockSymbol( string calldata _lockSymbol ) external onlyOwner { lockSymbol = _lockSymbol; emit NewLockSymbol(_lockSymbol); } /** * @dev Gets the token symbol * @return string representing the token name */ function symbol() external view returns(string memory) { if(bytes(lockSymbol).length == 0) { return unlockProtocol.getGlobalTokenSymbol(); } else { return lockSymbol; } } /** * Allows the Lock owner to update the baseTokenURI for this Lock. */ function setBaseTokenURI( string calldata _baseTokenURI ) external onlyOwner { baseTokenURI = _baseTokenURI; } /** @notice A distinct Uniform Resource Identifier (URI) for a given asset. * @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC * 3986. The URI may point to a JSON file that conforms to the "ERC721 * Metadata JSON Schema". * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ function tokenURI( uint256 _tokenId ) external view isKey(_tokenId) returns(string memory) { string memory URI; if(bytes(baseTokenURI).length == 0) { URI = unlockProtocol.getGlobalBaseTokenURI(); } else { URI = baseTokenURI; } return UnlockUtils.strConcat( URI, UnlockUtils.address2Str(address(this)), '/', UnlockUtils.uint2Str(_tokenId) ); } } // File: contracts/mixins/MixinNoFallback.sol pragma solidity 0.5.7; /** * @title Mixin for the fallback function implementation, which simply reverts. * @author HardlyDifficult * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinNoFallback { /** * @dev the fallback function should not be used. This explicitly reverts * to ensure it's never used. */ function() external { revert('NO_FALLBACK'); } } // File: openzeppelin-solidity/contracts/math/SafeMath.sol pragma solidity ^0.5.2; /** * @title SafeMath * @dev Unsigned math operations with safety checks that revert on error */ library SafeMath { /** * @dev Multiplies two unsigned integers, reverts on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Adds two unsigned integers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } } // File: contracts/mixins/MixinPurchase.sol pragma solidity 0.5.7; /** * @title Mixin for the purchase-related functions. * @author HardlyDifficult * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinPurchase is MixinFunds, MixinDisableAndDestroy, MixinLockCore, MixinKeys { using SafeMath for uint; /** * @dev Purchase function, public version, with no referrer. * @param _recipient address of the recipient of the purchased key */ function purchaseFor( address _recipient ) external payable onlyIfAlive { return _purchaseFor(_recipient, address(0)); } /** * @dev Purchase function, public version, with referrer. * @param _recipient address of the recipient of the purchased key * @param _referrer address of the user making the referral */ function purchaseForFrom( address _recipient, address _referrer ) external payable onlyIfAlive hasValidKey(_referrer) { return _purchaseFor(_recipient, _referrer); } /** * @dev Purchase function: this lets a user purchase a key from the lock for another user * @param _recipient address of the recipient of the purchased key * This will fail if * - the keyReleaseMechanism is private * - the keyReleaseMechanism is Approved and the recipient has not been previously approved * - the amount value is smaller than the price * - the recipient already owns a key * TODO: next version of solidity will allow for message to be added to require. */ function _purchaseFor( address _recipient, address _referrer ) private notSoldOut() { // solhint-disable-line function-max-lines require(_recipient != address(0), 'INVALID_ADDRESS'); // Let's get the actual price for the key from the Unlock smart contract uint discount; uint tokens; uint inMemoryKeyPrice = keyPrice; (discount, tokens) = unlockProtocol.computeAvailableDiscountFor(_recipient, inMemoryKeyPrice); uint netPrice = inMemoryKeyPrice; if (discount > inMemoryKeyPrice) { netPrice = 0; } else { // SafeSub not required as the if statement already confirmed `inMemoryKeyPrice - discount` cannot underflow netPrice = inMemoryKeyPrice - discount; } // We explicitly allow for greater amounts of ETH to allow 'donations' _chargeAtLeast(netPrice); // Assign the key Key storage toKey = _getKeyFor(_recipient); uint previousExpiration = toKey.expirationTimestamp; if (toKey.tokenId == 0) { _assignNewTokenId(toKey); _recordOwner(_recipient, toKey.tokenId); // SafeAdd is not required here since expirationDuration is capped to a tiny value // (relative to the size of a uint) toKey.expirationTimestamp = block.timestamp + expirationDuration; } else { // This is an existing owner trying to extend their key toKey.expirationTimestamp = previousExpiration.add(expirationDuration); } if (discount > 0) { unlockProtocol.recordConsumedDiscount(discount, tokens); } unlockProtocol.recordKeyPurchase(netPrice, _referrer); // trigger event emit Transfer( address(0), // This is a creation. _recipient, numberOfKeysSold ); } } // File: openzeppelin-solidity/contracts/cryptography/ECDSA.sol pragma solidity ^0.5.2; /** * @title Elliptic curve signature operations * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d * TODO Remove this library once solidity supports passing a signature to ecrecover. * See https://github.com/ethereum/solidity/issues/864 */ library ECDSA { /** * @dev Recover signer address from a message by using their signature * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address. * @param signature bytes signature, the signature is generated using web3.eth.sign() */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { return (address(0)); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return address(0); } if (v != 27 && v != 28) { return address(0); } // If the signature is valid (and not malleable), return the signer address return ecrecover(hash, v, r, s); } /** * toEthSignedMessageHash * @dev prefix a bytes32 value with "\x19Ethereum Signed Message:" * and hash the result */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } } // File: contracts/mixins/MixinRefunds.sol pragma solidity 0.5.7; contract MixinRefunds is Ownable, MixinFunds, MixinLockCore, MixinKeys { using SafeMath for uint; // CancelAndRefund will return funds based on time remaining minus this penalty. // This is calculated as `proRatedRefund * refundPenaltyNumerator / refundPenaltyDenominator`. uint public refundPenaltyNumerator = 1; uint public refundPenaltyDenominator = 10; // Stores a nonce per user to use for signed messages mapping(address => uint) public keyOwnerToNonce; event CancelKey( uint indexed tokenId, address indexed owner, address indexed sendTo, uint refund ); event RefundPenaltyChanged( uint oldRefundPenaltyNumerator, uint oldRefundPenaltyDenominator, uint refundPenaltyNumerator, uint refundPenaltyDenominator ); /** * @dev Destroys the user's key and sends a refund based on the amount of time remaining. */ function cancelAndRefund() external { _cancelAndRefund(msg.sender); } /** * @dev Cancels a key owned by a different user and sends the funds to the msg.sender. * @param _keyOwner this user's key will be canceled * @param _signature getCancelAndRefundApprovalHash signed by the _keyOwner */ function cancelAndRefundFor( address _keyOwner, bytes calldata _signature ) external { require( ECDSA.recover( ECDSA.toEthSignedMessageHash( getCancelAndRefundApprovalHash(_keyOwner, msg.sender) ), _signature ) == _keyOwner, 'INVALID_SIGNATURE' ); keyOwnerToNonce[_keyOwner]++; _cancelAndRefund(_keyOwner); } /** * @dev Increments the current nonce for the msg.sender. * This can be used to invalidate a previously signed message. */ function incrementNonce( ) external { keyOwnerToNonce[msg.sender]++; } /** * Allow the owner to change the refund penalty. */ function updateRefundPenalty( uint _refundPenaltyNumerator, uint _refundPenaltyDenominator ) external onlyOwner { require(_refundPenaltyDenominator != 0, 'INVALID_RATE'); emit RefundPenaltyChanged( refundPenaltyNumerator, refundPenaltyDenominator, _refundPenaltyNumerator, _refundPenaltyDenominator ); refundPenaltyNumerator = _refundPenaltyNumerator; refundPenaltyDenominator = _refundPenaltyDenominator; } /** * @dev Determines how much of a refund a key owner would receive if they issued * a cancelAndRefund block.timestamp. * Note that due to the time required to mine a tx, the actual refund amount will be lower * than what the user reads from this call. */ function getCancelAndRefundValueFor( address _owner ) external view returns (uint refund) { return _getCancelAndRefundValue(_owner); } /** * @dev returns the hash to sign in order to allow another user to cancel on your behalf. */ function getCancelAndRefundApprovalHash( address _keyOwner, address _txSender ) public view returns (bytes32 approvalHash) { return keccak256( abi.encodePacked( // Approval is specific to this Lock address(this), // Approval enables only one cancel call keyOwnerToNonce[_keyOwner], // Approval allows only one account to broadcast the tx _txSender ) ); } /** * @dev cancels the key for the given keyOwner and sends the refund to the msg.sender. */ function _cancelAndRefund( address _keyOwner ) internal { Key storage key = _getKeyFor(_keyOwner); uint refund = _getCancelAndRefundValue(_keyOwner); emit CancelKey(key.tokenId, _keyOwner, msg.sender, refund); // expirationTimestamp is a proxy for hasKey, setting this to `block.timestamp` instead // of 0 so that we can still differentiate hasKey from hasValidKey. key.expirationTimestamp = block.timestamp; if (refund > 0) { // Security: doing this last to avoid re-entrancy concerns _transfer(msg.sender, refund); } } /** * @dev Determines how much of a refund a key owner would receive if they issued * a cancelAndRefund now. * @param _owner The owner of the key check the refund value for. */ function _getCancelAndRefundValue( address _owner ) private view hasValidKey(_owner) returns (uint refund) { Key storage key = _getKeyFor(_owner); // Math: safeSub is not required since `hasValidKey` confirms timeRemaining is positive uint timeRemaining = key.expirationTimestamp - block.timestamp; if(timeRemaining >= expirationDuration) { refund = keyPrice; } else { // Math: using safeMul in case keyPrice or timeRemaining is very large refund = keyPrice.mul(timeRemaining) / expirationDuration; } uint penalty = keyPrice.mul(refundPenaltyNumerator) / refundPenaltyDenominator; if (refund > penalty) { // Math: safeSub is not required since the if confirms this won't underflow refund -= penalty; } else { refund = 0; } } } // File: openzeppelin-solidity/contracts/utils/Address.sol pragma solidity ^0.5.2; /** * Utility library of inline functions on addresses */ library Address { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param account address of the account to check * @return whether the target address is a contract */ function isContract(address account) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } // File: contracts/mixins/MixinTransfer.sol pragma solidity 0.5.7; /** * @title Mixin for the transfer-related functions needed to meet the ERC721 * standard. * @author Nick Furfaro * @dev `Mixins` are a design pattern seen in the 0x contracts. It simply * separates logically groupings of code to ease readability. */ contract MixinTransfer is MixinFunds, MixinLockCore, MixinKeys, MixinApproval { using SafeMath for uint; using Address for address; event TransferFeeChanged( uint oldTransferFeeNumerator, uint oldTransferFeeDenominator, uint transferFeeNumerator, uint transferFeeDenominator ); // 0x150b7a02 == bytes4(keccak256('onERC721Received(address,address,uint256,bytes)')) bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; // The fee relative to keyPrice to charge when transfering a Key to another account // (potentially on a 0x marketplace). // This is calculated as `keyPrice * transferFeeNumerator / transferFeeDenominator`. uint public transferFeeNumerator = 0; uint public transferFeeDenominator = 100; /** * This is payable because at some point we want to allow the LOCK to capture a fee on 2ndary * market transactions... */ function transferFrom( address _from, address _recipient, uint _tokenId ) public payable onlyIfAlive hasValidKey(_from) onlyKeyOwnerOrApproved(_tokenId) { require(_recipient != address(0), 'INVALID_ADDRESS'); _chargeAtLeast(getTransferFee(_from)); Key storage fromKey = _getKeyFor(_from); Key storage toKey = _getKeyFor(_recipient); uint previousExpiration = toKey.expirationTimestamp; if (toKey.tokenId == 0) { toKey.tokenId = fromKey.tokenId; _recordOwner(_recipient, toKey.tokenId); } if (previousExpiration <= block.timestamp) { // The recipient did not have a key, or had a key but it expired. The new expiration is the // sender's key expiration // an expired key is no longer a valid key, so the new tokenID is the sender's tokenID toKey.expirationTimestamp = fromKey.expirationTimestamp; toKey.tokenId = fromKey.tokenId; _recordOwner(_recipient, _tokenId); } else { // The recipient has a non expired key. We just add them the corresponding remaining time // SafeSub is not required since the if confirms `previousExpiration - block.timestamp` cannot underflow toKey.expirationTimestamp = fromKey .expirationTimestamp.add(previousExpiration - block.timestamp); } // Effectively expiring the key for the previous owner fromKey.expirationTimestamp = block.timestamp; // Set the tokenID to 0 for the previous owner to avoid duplicates fromKey.tokenId = 0; // Clear any previous approvals _clearApproval(_tokenId); // trigger event emit Transfer( _from, _recipient, _tokenId ); } /** * @notice Transfers the ownership of an NFT from one address to another address * @dev This works identically to the other function with an extra data parameter, * except this function just sets data to '' * @param _from The current owner of the NFT * @param _to The new owner * @param _tokenId The NFT to transfer */ function safeTransferFrom( address _from, address _to, uint _tokenId ) external payable { safeTransferFrom(_from, _to, _tokenId, ''); } /** * @notice Transfers the ownership of an NFT from one address to another address. * When transfer is complete, this functions * checks if `_to` is a smart contract (code size > 0). If so, it calls * `onERC721Received` on `_to` and throws if the return value is not * `bytes4(keccak256('onERC721Received(address,address,uint,bytes)'))`. * @param _from The current owner of the NFT * @param _to The new owner * @param _tokenId The NFT to transfer * @param _data Additional data with no specified format, sent in call to `_to` */ function safeTransferFrom( address _from, address _to, uint _tokenId, bytes memory _data ) public payable onlyIfAlive onlyKeyOwnerOrApproved(_tokenId) hasValidKey(ownerOf(_tokenId)) { transferFrom(_from, _to, _tokenId); require(_checkOnERC721Received(_from, _to, _tokenId, _data), 'NON_COMPLIANT_ERC721_RECEIVER'); } /** * Allow the Lock owner to change the transfer fee. */ function updateTransferFee( uint _transferFeeNumerator, uint _transferFeeDenominator ) external onlyOwner { require(_transferFeeDenominator != 0, 'INVALID_RATE'); emit TransferFeeChanged( transferFeeNumerator, transferFeeDenominator, _transferFeeNumerator, _transferFeeDenominator ); transferFeeNumerator = _transferFeeNumerator; transferFeeDenominator = _transferFeeDenominator; } /** * Determines how much of a fee a key owner would need to pay in order to * transfer the key to another account. This is pro-rated so the fee goes down * overtime. * @param _owner The owner of the key check the transfer fee for. */ function getTransferFee( address _owner ) public view hasValidKey(_owner) returns (uint) { Key storage key = _getKeyFor(_owner); // Math: safeSub is not required since `hasValidKey` confirms timeRemaining is positive uint timeRemaining = key.expirationTimestamp - block.timestamp; uint fee; if(timeRemaining >= expirationDuration) { // Max the potential impact of this fee for keys with long durations remaining fee = keyPrice; } else { // Math: using safeMul in case keyPrice or timeRemaining is very large fee = keyPrice.mul(timeRemaining) / expirationDuration; } return fee.mul(transferFeeNumerator) / transferFeeDenominator; } /** * @dev Internal function to invoke `onERC721Received` on a target address * The call is not executed if the target address is not a contract * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) internal returns (bool) { if (!to.isContract()) { return true; } bytes4 retval = IERC721Receiver(to).onERC721Received( msg.sender, from, tokenId, _data); return (retval == _ERC721_RECEIVED); } } // File: contracts/PublicLock.sol pragma solidity 0.5.7; /** * @title The Lock contract * @author Julien Genestoux (unlock-protocol.com) * Eventually: implement ERC721. * @dev ERC165 allows our contract to be queried to determine whether it implements a given interface. * Every ERC-721 compliant contract must implement the ERC165 interface. * https://eips.ethereum.org/EIPS/eip-721 */ contract PublicLock is IERC721, MixinNoFallback, ERC165, Ownable, ERC721Holder, MixinFunds, MixinDisableAndDestroy, MixinLockCore, MixinKeys, MixinLockMetadata, MixinGrantKeys, MixinPurchase, MixinApproval, MixinTransfer, MixinRefunds { constructor( address _owner, uint _expirationDuration, address _tokenAddress, uint _keyPrice, uint _maxNumberOfKeys, string memory _lockName ) public MixinFunds(_tokenAddress) MixinLockCore(_expirationDuration, _keyPrice, _maxNumberOfKeys) MixinLockMetadata(_lockName) { // registering the interface for erc721 with ERC165.sol using // the ID specified in the standard: https://eips.ethereum.org/EIPS/eip-721 _registerInterface(0x80ac58cd); // We must manually initialize Ownable.sol Ownable.initialize(_owner); } // The version number of the current implementation on this network function publicLockVersion( ) external pure returns (uint16) { return 3; } }
[{"constant":true,"inputs":[{"name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"owners","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_approved","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"refundPenaltyDenominator","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"refundPenaltyNumerator","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"unlockProtocol","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_page","type":"uint256"},{"name":"_pageSize","type":"uint256"}],"name":"getOwnersByPage","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"keyPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"expirationDuration","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"name":"","type":"bytes4"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_keyPrice","type":"uint256"}],"name":"updateKeyPrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"cancelAndRefund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_recipient","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_baseTokenURI","type":"string"}],"name":"setBaseTokenURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_refundPenaltyNumerator","type":"uint256"},{"name":"_refundPenaltyDenominator","type":"uint256"}],"name":"updateRefundPenalty","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"numberOfKeysSold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_transferFeeNumerator","type":"uint256"},{"name":"_transferFeeDenominator","type":"uint256"}],"name":"updateTransferFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isAlive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_a","type":"string"},{"name":"_b","type":"string"},{"name":"_c","type":"string"},{"name":"_d","type":"string"}],"name":"strConcat","outputs":[{"name":"_concatenatedString","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"keyOwnerToNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_i","type":"uint256"}],"name":"uint2Str","outputs":[{"name":"_uintAsString","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getCancelAndRefundValueFor","outputs":[{"name":"refund","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lockName","type":"string"}],"name":"updateLockName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"address2Str","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"incrementNonce","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getHasValidKey","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_referrer","type":"address"}],"name":"purchaseForFrom","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"partialWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxNumberOfKeys","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lockSymbol","type":"string"}],"name":"updateLockSymbol","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipients","type":"address[]"},{"name":"_expirationTimestamps","type":"uint256[]"}],"name":"grantKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getTransferFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_keyOwner","type":"address"},{"name":"_txSender","type":"address"}],"name":"getCancelAndRefundApprovalHash","outputs":[{"name":"approvalHash","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"transferFeeNumerator","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"numberOfOwners","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"getTokenIdFor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_owner","type":"address"}],"name":"isKeyOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_expirationTimestamp","type":"uint256"}],"name":"grantKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"tokenAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"expireKeyFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"destroyLock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"keyExpirationTimestampFor","outputs":[{"name":"timestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_keyOwner","type":"address"},{"name":"_signature","type":"bytes"}],"name":"cancelAndRefundFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"disableLock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"publicLockVersion","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"transferFeeDenominator","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"}],"name":"purchaseFor","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_recipients","type":"address[]"},{"name":"_expirationTimestamp","type":"uint256"}],"name":"grantKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_owner","type":"address"},{"name":"_expirationDuration","type":"uint256"},{"name":"_tokenAddress","type":"address"},{"name":"_keyPrice","type":"uint256"},{"name":"_maxNumberOfKeys","type":"uint256"},{"name":"_lockName","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"tokenId","type":"uint256"},{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"sendTo","type":"address"},{"indexed":false,"name":"refund","type":"uint256"}],"name":"CancelKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldRefundPenaltyNumerator","type":"uint256"},{"indexed":false,"name":"oldRefundPenaltyDenominator","type":"uint256"},{"indexed":false,"name":"refundPenaltyNumerator","type":"uint256"},{"indexed":false,"name":"refundPenaltyDenominator","type":"uint256"}],"name":"RefundPenaltyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldTransferFeeNumerator","type":"uint256"},{"indexed":false,"name":"oldTransferFeeDenominator","type":"uint256"},{"indexed":false,"name":"transferFeeNumerator","type":"uint256"},{"indexed":false,"name":"transferFeeDenominator","type":"uint256"}],"name":"TransferFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"symbol","type":"string"}],"name":"NewLockSymbol","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"tokenId","type":"uint256"}],"name":"ExpireKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldKeyPrice","type":"uint256"},{"indexed":false,"name":"keyPrice","type":"uint256"}],"name":"PriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"balance","type":"uint256"},{"indexed":true,"name":"owner","type":"address"}],"name":"Destroy","type":"event"},{"anonymous":false,"inputs":[],"name":"Disable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":true,"name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_approved","type":"address"},{"indexed":true,"name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_operator","type":"address"},{"indexed":false,"name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"}]
Contract Creation Code
6080604052600060755560646076556001607755600a6078553480156200002557600080fd5b50604051620049ab380380620049ab833981018060405260c08110156200004b57600080fd5b8151602083015160408401516060850151608086015160a087018051959794969395929491938201926401000000008111156200008757600080fd5b820160208101848111156200009b57600080fd5b8151640100000000811182820187101715620000b657600080fd5b50509291905050508085848487620000db6301ffc9a760e01b6200030260201b60201c565b6001600160a01b03811615806200015957506000816001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200012957600080fd5b505afa1580156200013e573d6000803e3d6000fd5b505050506040513d60208110156200015557600080fd5b5051115b620001c557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f494e56414c49445f544f4b454e00000000000000000000000000000000000000604482015290519081900360640190fd5b60678054600160a01b60ff02196001600160a01b039093166001600160a01b031990911617919091167401000000000000000000000000000000000000000017905563bbf81e008311156200027b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d41585f45585049524154494f4e5f3130305f59454152530000000000000000604482015290519081900360640190fd5b606880546001600160a01b03191633179055606992909255606a55606b558051620002ae90607090602084019062000488565b50620002c7635b5e139f60e01b6200030260201b60201c565b50620002e06380ac58cd60e01b6200030260201b60201c565b620002f6866200036f60201b62002ff81760201c565b5050505050506200052a565b7fffffffff0000000000000000000000000000000000000000000000000000000080821614156200033257600080fd5b7fffffffff00000000000000000000000000000000000000000000000000000000166000908152602081905260409020805460ff19166001179055565b600154610100900460ff1680620003915750620003916200048160201b60201c565b80620003a0575060015460ff16155b620003f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e8152602001806200497d602e913960400191505060405180910390fd5b6001805461010061ff00198216811760ff19168317909255603480546001600160a01b0319166001600160a01b0385811691909117918290556040519390920460ff16929116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3600180549115156101000261ff001990921691909117905550565b303b155b90565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620004cb57805160ff1916838001178555620004fb565b82800160010185558215620004fb579182015b82811115620004fb578251825591602001919060010190620004de565b50620005099291506200050d565b5090565b6200048591905b8082111562000509576000815560010162000514565b614443806200053a6000396000f3fe6080604052600436106103ce5760003560e01c806370a08231116101fd5780639b3f0b1711610118578063c1c98d03116100ab578063d42cfc411161007a578063d42cfc411461136e578063e985e9c514611383578063f2fde38b146113be578063f6e4641f146113f1578063f8faf94214611417576103ce565b8063c1c98d03146112d0578063c4d66de8146112e5578063c87b56dd14611318578063d1bbd49c14611342576103ce565b8063a843a4e7116100e7578063a843a4e714611139578063abdf82ce1461114e578063b88d4fde14611181578063b8968bb414611245576103ce565b80639b3f0b171461107d5780639d76ea58146110b65780639f98d3cb146110cb578063a22cb465146110fe576103ce565b80638d0361fc1161019057806393fd18441161015f57806393fd184414610fe757806395d89b4114610ffc578063970aaeb714611011578063994a8a7114611044576103ce565b80638d0361fc14610f6d5780638da5cb5b14610fa85780638f32d59b14610fbd5780638f98ce8f14610fd2576103ce565b806374b6c106116101cc57806374b6c10614610ddf578063782a4ade14610df45780637c7c425314610e6f57806383cb0fa914610f3a576103ce565b806370a0823114610d3f57806370efb77014610d72578063715018a614610da057806371d2ee6c14610db5576103ce565b806330176e13116102ed5780634bc5a135116102805780635fdb97e11161024f5780635fdb97e114610c9a578063627cdcb914610ccd5780636352211e14610ce25780636d8ea5b414610d0c576103ce565b80634bc5a13514610b8f5780634c7a12a014610bc257806352d6a8e414610bec578063550ef3a814610c1f576103ce565b80633d3359cb116102bc5780633d3359cb146108d45780634136aa351461090457806342842e0e1461091957806345e965cd1461094f576103ce565b806330176e13146107ff57806339f469861461087a5780633ba70e31146108aa5780633ccfd60b146108bf576103ce565b806310803b721161036557806318160ddd1161033457806318160ddd146107755780631f1ec0291461078a5780632009dc65146107b457806323b872dd146107c9576103ce565b806310803b72146105dd57806310e569731461065d57806311a4c03a14610672578063150b7a0214610687576103ce565b8063095ea7b3116103a1578063095ea7b31461055e5780630c79130f1461058c5780630ed3e2cc146105b35780630f15023b146105c8576103ce565b806301ffc9a71461041c578063025e7c271461046457806306fdde03146104aa578063081812fc14610534575b3480156103da57600080fd5b5060408051600160e51b62461bcd02815260206004820152600b6024820152600160a81b6a4e4f5f46414c4c4241434b02604482015290519081900360640190fd5b34801561042857600080fd5b506104506004803603602081101561043f57600080fd5b50356001600160e01b031916611492565b604080519115158252519081900360200190f35b34801561047057600080fd5b5061048e6004803603602081101561048757600080fd5b50356114b5565b604080516001600160a01b039092168252519081900360200190f35b3480156104b657600080fd5b506104bf6114dc565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104f95781810151838201526020016104e1565b50505050905090810190601f1680156105265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561054057600080fd5b5061048e6004803603602081101561055757600080fd5b5035611573565b61058a6004803603604081101561057457600080fd5b506001600160a01b038135169060200135611584565b005b34801561059857600080fd5b506105a1611723565b60408051918252519081900360200190f35b3480156105bf57600080fd5b506105a1611729565b3480156105d457600080fd5b5061048e61172f565b3480156105e957600080fd5b5061060d6004803603604081101561060057600080fd5b508035906020013561173e565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610649578181015183820152602001610631565b505050509050019250505060405180910390f35b34801561066957600080fd5b506105a1611863565b34801561067e57600080fd5b506105a1611869565b34801561069357600080fd5b50610758600480360360808110156106aa57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156106e457600080fd5b8201836020820111156106f657600080fd5b803590602001918460018302840111600160201b8311171561071757600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061186f945050505050565b604080516001600160e01b03199092168252519081900360200190f35b34801561078157600080fd5b506105a1611883565b34801561079657600080fd5b5061058a600480360360208110156107ad57600080fd5b5035611889565b3480156107c057600080fd5b5061058a611937565b61058a600480360360608110156107df57600080fd5b506001600160a01b03813581169160208101359091169060400135611942565b34801561080b57600080fd5b5061058a6004803603602081101561082257600080fd5b810190602081018135600160201b81111561083c57600080fd5b82018360208201111561084e57600080fd5b803590602001918460018302840111600160201b8311171561086f57600080fd5b509092509050611ba4565b34801561088657600080fd5b5061058a6004803603604081101561089d57600080fd5b5080359060200135611bc6565b3480156108b657600080fd5b506105a1611c76565b3480156108cb57600080fd5b5061058a611c7c565b3480156108e057600080fd5b5061058a600480360360408110156108f757600080fd5b5080359060200135611cf4565b34801561091057600080fd5b50610450611da4565b61058a6004803603606081101561092f57600080fd5b506001600160a01b03813581169160208101359091169060400135611db4565b34801561095b57600080fd5b506104bf6004803603608081101561097257600080fd5b810190602081018135600160201b81111561098c57600080fd5b82018360208201111561099e57600080fd5b803590602001918460018302840111600160201b831117156109bf57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610a1157600080fd5b820183602082011115610a2357600080fd5b803590602001918460018302840111600160201b83111715610a4457600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610a9657600080fd5b820183602082011115610aa857600080fd5b803590602001918460018302840111600160201b83111715610ac957600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610b1b57600080fd5b820183602082011115610b2d57600080fd5b803590602001918460018302840111600160201b83111715610b4e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611dcf945050505050565b348015610b9b57600080fd5b506105a160048036036020811015610bb257600080fd5b50356001600160a01b0316611f84565b348015610bce57600080fd5b506104bf60048036036020811015610be557600080fd5b5035611f96565b348015610bf857600080fd5b506105a160048036036020811015610c0f57600080fd5b50356001600160a01b031661205d565b348015610c2b57600080fd5b5061058a60048036036020811015610c4257600080fd5b810190602081018135600160201b811115610c5c57600080fd5b820183602082011115610c6e57600080fd5b803590602001918460018302840111600160201b83111715610c8f57600080fd5b509092509050612068565b348015610ca657600080fd5b506104bf60048036036020811015610cbd57600080fd5b50356001600160a01b0316612085565b348015610cd957600080fd5b5061058a61221d565b348015610cee57600080fd5b5061048e60048036036020811015610d0557600080fd5b5035612235565b348015610d1857600080fd5b5061045060048036036020811015610d2f57600080fd5b50356001600160a01b03166122b1565b348015610d4b57600080fd5b506105a160048036036020811015610d6257600080fd5b50356001600160a01b03166122d1565b61058a60048036036040811015610d8857600080fd5b506001600160a01b0381358116916020013516612346565b348015610dac57600080fd5b5061058a6123f7565b348015610dc157600080fd5b5061058a60048036036020811015610dd857600080fd5b5035612452565b348015610deb57600080fd5b506105a1612523565b348015610e0057600080fd5b5061058a60048036036020811015610e1757600080fd5b810190602081018135600160201b811115610e3157600080fd5b820183602082011115610e4357600080fd5b803590602001918460018302840111600160201b83111715610e6457600080fd5b509092509050612529565b348015610e7b57600080fd5b5061058a60048036036040811015610e9257600080fd5b810190602081018135600160201b811115610eac57600080fd5b820183602082011115610ebe57600080fd5b803590602001918460208302840111600160201b83111715610edf57600080fd5b919390929091602081019035600160201b811115610efc57600080fd5b820183602082011115610f0e57600080fd5b803590602001918460208302840111600160201b83111715610f2f57600080fd5b5090925090506125ab565b348015610f4657600080fd5b506105a160048036036020811015610f5d57600080fd5b50356001600160a01b031661260d565b348015610f7957600080fd5b506105a160048036036040811015610f9057600080fd5b506001600160a01b03813581169160200135166126d6565b348015610fb457600080fd5b5061048e61272d565b348015610fc957600080fd5b5061045061273c565b348015610fde57600080fd5b506105a161274d565b348015610ff357600080fd5b506105a1612753565b34801561100857600080fd5b506104bf612759565b34801561101d57600080fd5b506105a16004803603602081101561103457600080fd5b50356001600160a01b03166128e4565b34801561105057600080fd5b506104506004803603604081101561106757600080fd5b50803590602001356001600160a01b0316612954565b34801561108957600080fd5b5061058a600480360360408110156110a057600080fd5b506001600160a01b038135169060200135612975565b3480156110c257600080fd5b5061048e612990565b3480156110d757600080fd5b5061058a600480360360208110156110ee57600080fd5b50356001600160a01b031661299f565b34801561110a57600080fd5b5061058a6004803603604081101561112157600080fd5b506001600160a01b0381351690602001351515612a5c565b34801561114557600080fd5b5061058a612b73565b34801561115a57600080fd5b506105a16004803603602081101561117157600080fd5b50356001600160a01b0316612c32565b61058a6004803603608081101561119757600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156111d157600080fd5b8201836020820111156111e357600080fd5b803590602001918460018302840111600160201b8311171561120457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612cc4945050505050565b34801561125157600080fd5b5061058a6004803603604081101561126857600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561129257600080fd5b8201836020820111156112a457600080fd5b803590602001918460018302840111600160201b831117156112c557600080fd5b509092509050612e67565b3480156112dc57600080fd5b5061058a612f48565b3480156112f157600080fd5b5061058a6004803603602081101561130857600080fd5b50356001600160a01b0316612ff8565b34801561132457600080fd5b506104bf6004803603602081101561133b57600080fd5b50356130e7565b34801561134e57600080fd5b50611357613308565b6040805161ffff9092168252519081900360200190f35b34801561137a57600080fd5b506105a161330d565b34801561138f57600080fd5b50610450600480360360408110156113a657600080fd5b506001600160a01b0381358116916020013516613313565b3480156113ca57600080fd5b5061058a600480360360208110156113e157600080fd5b50356001600160a01b0316613341565b61058a6004803603602081101561140757600080fd5b50356001600160a01b031661335b565b34801561142357600080fd5b5061058a6004803603604081101561143a57600080fd5b810190602081018135600160201b81111561145457600080fd5b82018360208201111561146657600080fd5b803590602001918460208302840111600160201b8311171561148757600080fd5b9193509150356133bc565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b606f81815481106114c257fe5b6000918252602090912001546001600160a01b0316905081565b60708054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156115685780601f1061153d57610100808354040283529160200191611568565b820191906000526020600020905b81548152906001019060200180831161154b57829003601f168201915b505050505090505b90565b600061157e8261340b565b92915050565b606754600160a01b900460ff166115da5760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b806115e58133612954565b806115f557506115f58133613478565b8061160d575061160d61160782612235565b33613313565b6116615760408051600160e51b62461bcd02815260206004820152601a60248201527f4f4e4c595f4b45595f4f574e45525f4f525f415050524f564544000000000000604482015290519081900360640190fd5b336001600160a01b03841614156116b45760408051600160e51b62461bcd02815260206004820152600c6024820152600160a11b6b20a8282927ab22afa9a2a62302604482015290519081900360640190fd5b600082815260736020526040902080546001600160a01b0319166001600160a01b03851690811790915582906116e982612235565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b60785481565b60775481565b6068546001600160a01b031681565b606f546060906117985760408051600160e51b62461bcd02815260206004820152601360248201527f4e4f5f4f55545354414e44494e475f4b45595300000000000000000000000000604482015290519081900360640190fd5b606f5482908482029060009082840111156117bb5750606f5481810392506117c0565b508082015b6060836040519080825280602002602001820160405280156117ec578160200160208202803883390190505b5090506000835b8381101561185657606f818154811061180857fe5b9060005260206000200160009054906101000a90046001600160a01b031683838151811061183257fe5b6001600160a01b0390921660209283029190910190910152600191820191016117f3565b5090979650505050505050565b606a5481565b60695481565b600160e11b630a85bd01025b949350505050565b606c5490565b61189161273c565b61189a57600080fd5b606754600160a01b900460ff166118f05760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b606a805490829055604080518281526020810184905281517f8aa4fa52648a6d15edce8a179c792c86f3719d0cc3c572cf90f91948f0f2cb68929181900390910190a15050565b61194033613499565b565b606754600160a01b900460ff166119985760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b826119a2816122b1565b6119e95760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b816119f48133612954565b80611a045750611a048133613478565b80611a165750611a1661160782612235565b611a6a5760408051600160e51b62461bcd02815260206004820152601a60248201527f4f4e4c595f4b45595f4f574e45525f4f525f415050524f564544000000000000604482015290519081900360640190fd5b6001600160a01b038416611abd5760408051600160e51b62461bcd02815260206004820152600f6024820152600160881b6e494e56414c49445f4144445245535302604482015290519081900360640190fd5b611ace611ac98661260d565b61350e565b6000611ad986613740565b90506000611ae686613740565b6001810154815491925090611b05578254808355611b0590889061375a565b428111611b29576001808401549083015582548255611b24878761375a565b611b46565b6001830154611b409042830363ffffffff6137e116565b60018301555b42600184015560008355611b59866137fa565b85876001600160a01b0316896001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050505050565b611bac61273c565b611bb557600080fd5b611bc160728383614351565b505050565b611bce61273c565b611bd757600080fd5b80611c1e5760408051600160e51b62461bcd02815260206004820152600c6024820152600160a01b6b494e56414c49445f5241544502604482015290519081900360640190fd5b60775460785460408051928352602083019190915281810184905260608201839052517fa7d13855fe99b8c8b2780f36ff9e06133878b66a664a951b2375fe2296cc00089181900360800190a1607791909155607855565b606c5481565b611c8461273c565b611c8d57600080fd5b6000611c9830613835565b905060008111611ce85760408051600160e51b62461bcd0281526020600482015260106024820152600160801b6f4e4f545f454e4f5547485f46554e445302604482015290519081900360640190fd5b611cf1816138dc565b50565b611cfc61273c565b611d0557600080fd5b80611d4c5760408051600160e51b62461bcd02815260206004820152600c6024820152600160a01b6b494e56414c49445f5241544502604482015290519081900360640190fd5b60755460765460408051928352602083019190915281810184905260608201839052517ff0cc3b8bd450a20cce7720453e064b35cf490baa5d53c7c6ef8b2e1b02898a7d9181900360800190a1607591909155607655565b606754600160a01b900460ff1681565b611bc183838360405180602001604052806000815250612cc4565b606080859050606085905060608590506060859050606081518351855187510101016040519080825280601f01601f191660200182016040528015611e1b576020820181803883390190505b509050806000805b8751811015611e7457878181518110611e3857fe5b602001015160f81c60f81b838380600101945081518110611e5557fe5b60200101906001600160f81b031916908160001a905350600101611e23565b5060005b8651811015611ec957868181518110611e8d57fe5b602001015160f81c60f81b838380600101945081518110611eaa57fe5b60200101906001600160f81b031916908160001a905350600101611e78565b5060005b8551811015611f1e57858181518110611ee257fe5b602001015160f81c60f81b838380600101945081518110611eff57fe5b60200101906001600160f81b031916908160001a905350600101611ecd565b5060005b8451811015611f7357848181518110611f3757fe5b602001015160f81c60f81b838380600101945081518110611f5457fe5b60200101906001600160f81b031916908160001a905350600101611f22565b50909b9a5050505050505050505050565b60796020526000908152604090205481565b60608180611fc05750506040805180820190915260018152600160fc1b60030260208201526114b0565b8260005b8115611fd857600101600a82049150611fc4565b6060816040519080825280601f01601f191660200182016040528015612005576020820181803883390190505b50905060001982015b841561205357600a850660300160f81b8282806001900393508151811061203157fe5b60200101906001600160f81b031916908160001a905350600a8504945061200e565b5095945050505050565b600061157e82613926565b61207061273c565b61207957600080fd5b611bc160708383614351565b604080518082018252601081527f303132333435363738396162636465660000000000000000000000000000000060208201528151602a80825260608281019094526001600160a01b03851692918491602082018180388339019050509050600160fc1b600302816000815181106120f957fe5b60200101906001600160f81b031916908160001a905350600160fb1b600f028160018151811061212557fe5b60200101906001600160f81b031916908160001a90535060005b6014811015612214578260048583600c016020811061215a57fe5b1a60f81b6001600160f81b031916901c60f81c60ff168151811061217a57fe5b602001015160f81c60f81b82826002026002018151811061219757fe5b60200101906001600160f81b031916908160001a905350828482600c01602081106121be57fe5b1a60f81b600f60f81b1660f81c60ff16815181106121d857fe5b602001015160f81c60f81b8282600202600301815181106121f557fe5b60200101906001600160f81b031916908160001a90535060010161213f565b50949350505050565b33600090815260796020526040902080546001019055565b6000818152606e602052604081205482906001600160a01b03166122945760408051600160e51b62461bcd02815260206004820152600b6024820152600160a81b6a4e4f5f535543485f4b455902604482015290519081900360640190fd5b50506000908152606e60205260409020546001600160a01b031690565b6001600160a01b03166000908152606d6020526040902060010154421090565b60006001600160a01b0382166123265760408051600160e51b62461bcd02815260206004820152600f6024820152600160881b6e494e56414c49445f4144445245535302604482015290519081900360640190fd5b61232f826122b1565b61233a57600061233d565b60015b60ff1692915050565b606754600160a01b900460ff1661239c5760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b806123a6816122b1565b6123ed5760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b611bc18383613a0b565b6123ff61273c565b61240857600080fd5b6034546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603480546001600160a01b0319169055565b61245a61273c565b61246357600080fd5b600081116124bb5760408051600160e51b62461bcd02815260206004820152601160248201527f475245415445525f5448414e5f5a45524f000000000000000000000000000000604482015290519081900360640190fd5b60006124c630613835565b9050818110156125165760408051600160e51b62461bcd0281526020600482015260106024820152600160801b6f4e4f545f454e4f5547485f46554e445302604482015290519081900360640190fd5b61251f826138dc565b5050565b606b5481565b61253161273c565b61253a57600080fd5b61254660718383614351565b507f8868e22e84ebf32da89b2ebcb0ac642816304ea3863b257f240df9098719cb97828260405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a15050565b6125b361273c565b6125bc57600080fd5b60005b83811015612606576125fe8585838181106125d657fe5b905060200201356001600160a01b03168484848181106125f257fe5b90506020020135613cf1565b6001016125bf565b5050505050565b600081612619816122b1565b6126605760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b600061266b84613740565b905060004282600101540390506000606954821061268c5750606a546126ad565b606954606a546126a2908463ffffffff613e0716565b816126a957fe5b0490505b6076546075546126c490839063ffffffff613e0716565b816126cb57fe5b049695505050505050565b6001600160a01b0391821660009081526079602090815260409182902054825130606090811b8285015260348201929092529390941690931b60548301528051808303604801815260689092019052805191012090565b6034546001600160a01b031690565b6034546001600160a01b0316331490565b60755481565b606f5490565b6071546060906002600019610100600184161502019091160461285257606860009054906101000a90046001600160a01b03166001600160a01b03166335a750de6040518163ffffffff1660e01b815260040160006040518083038186803b1580156127c457600080fd5b505afa1580156127d8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561280157600080fd5b810190808051600160201b81111561281857600080fd5b8201602081018481111561282b57600080fd5b8151600160201b81118282018710171561284457600080fd5b509094506115709350505050565b6071805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156128d85780601f106128ad576101008083540402835291602001916128d8565b820191906000526020600020905b8154815290600101906020018083116128bb57829003601f168201915b50505050509050611570565b6000816128f0816122b1565b6129375760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b50506001600160a01b03166000908152606d602052604090205490565b6000918252606e6020526040909120546001600160a01b0391821691161490565b61297d61273c565b61298657600080fd5b61251f8282613cf1565b6067546001600160a01b031681565b6129a761273c565b6129b057600080fd5b806129ba816122b1565b612a015760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b6001600160a01b0382166000908152606d602090815260409182902042600182015580548351908152925190927f59f2fe866dd27a1c2d34115520888c3150365cbc931aab97fa88c4b9ab40b79592908290030190a1505050565b606754600160a01b900460ff16612ab25760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b6001600160a01b038216331415612b055760408051600160e51b62461bcd02815260206004820152600c6024820152600160a11b6b20a8282927ab22afa9a2a62302604482015290519081900360640190fd5b3360008181526074602090815260408083206001600160a01b03871680855290835292819020805460ff1916861515908117909155815190815290519293927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31929181900390910190a35050565b612b7b61273c565b612b8457600080fd5b606754600160a01b900460ff1615612be65760408051600160e51b62461bcd02815260206004820152600d60248201527f44495341424c455f464952535400000000000000000000000000000000000000604482015290519081900360640190fd5b6040805130318152905133917fa053f2a7eceda47dde76e5939c5adf7b771e665fc84c8ef6feffc290a1eb1feb919081900360200190a2612c2f33612c2a30613835565b613e2e565b33ff5b6001600160a01b0381166000908152606d60205260408120600101548290612ca45760408051600160e51b62461bcd02815260206004820152601360248201527f4841535f4e455645525f4f574e45445f4b455900000000000000000000000000604482015290519081900360640190fd5b50506001600160a01b03166000908152606d602052604090206001015490565b606754600160a01b900460ff16612d1a5760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b81612d258133612954565b80612d355750612d358133613478565b80612d475750612d4761160782612235565b612d9b5760408051600160e51b62461bcd02815260206004820152601a60248201527f4f4e4c595f4b45595f4f574e45525f4f525f415050524f564544000000000000604482015290519081900360640190fd5b612da483612235565b612dad816122b1565b612df45760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b612dff868686611942565b612e0b86868686614049565b612e5f5760408051600160e51b62461bcd02815260206004820152601d60248201527f4e4f4e5f434f4d504c49414e545f4552433732315f5245434549564552000000604482015290519081900360640190fd5b505050505050565b826001600160a01b0316612ec2612e86612e8186336126d6565b614182565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141d392505050565b6001600160a01b031614612f205760408051600160e51b62461bcd02815260206004820152601160248201527f494e56414c49445f5349474e4154555245000000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b038316600090815260796020526040902080546001019055611bc183613499565b612f5061273c565b612f5957600080fd5b606754600160a01b900460ff16612faf5760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b6040517f25a311358326fb18c62efc24bc28d3126acee8d2a67fd8b2145b757dc8bd1bc190600090a16067805474ff000000000000000000000000000000000000000019169055565b600154610100900460ff168061301157506130116142c1565b8061301f575060015460ff16155b61305d57604051600160e51b62461bcd02815260040180806020018281038252602e8152602001806143ea602e913960400191505060405180910390fd5b6001805461010061ff00198216811760ff19168317909255603480546001600160a01b0319166001600160a01b0385811691909117918290556040519390920460ff16929116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3600180549115156101000261ff001990921691909117905550565b6000818152606e602052604090205460609082906001600160a01b03166131495760408051600160e51b62461bcd02815260206004820152600b6024820152600160a81b6a4e4f5f535543485f4b455902604482015290519081900360640190fd5b6072546060906002600019610100600184161502019091160461324257606860009054906101000a90046001600160a01b03166001600160a01b0316637ff94bb26040518163ffffffff1660e01b815260040160006040518083038186803b1580156131b457600080fd5b505afa1580156131c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156131f157600080fd5b810190808051600160201b81111561320857600080fd5b8201602081018481111561321b57600080fd5b8151600160201b81118282018710171561323457600080fd5b509094506132d09350505050565b6072805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156132c85780601f1061329d576101008083540402835291602001916132c8565b820191906000526020600020905b8154815290600101906020018083116132ab57829003601f168201915b505050505090505b61187b816132dd30612085565b604051806040016040528060018152602001600160f81b602f0281525061330388611f96565b611dcf565b600390565b60765481565b6001600160a01b03918216600090815260746020908152604080832093909416825291909152205460ff1690565b61334961273c565b61335257600080fd5b611cf1816142c7565b606754600160a01b900460ff166133b15760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1313d0d2d7d11154149150d055115102604482015290519081900360640190fd5b611cf1816000613a0b565b6133c461273c565b6133cd57600080fd5b60005b82811015613405576133fd8484838181106133e757fe5b905060200201356001600160a01b031683613cf1565b6001016133d0565b50505050565b6000818152607360205260408120546001600160a01b03168061157e5760408051600160e51b62461bcd02815260206004820152600d60248201527f4e4f4e455f415050524f56454400000000000000000000000000000000000000604482015290519081900360640190fd5b600091825260736020526040909120546001600160a01b0391821691161490565b60006134a482613740565b905060006134b183613926565b825460408051838152905192935033926001600160a01b03871692917f0a7068a9989857441c039a14a42b67ed71dd1fcfe5a9b17cc87b252e47bce528919081900360200190a44260018301558015611bc157611bc13382613e2e565b8015611cf1576067546001600160a01b031661357757803410156135725760408051600160e51b62461bcd0281526020600482015260106024820152600160801b6f4e4f545f454e4f5547485f46554e445302604482015290519081900360640190fd5b611cf1565b60675460408051600160e01b6370a0823102815230600482015290516001600160a01b039092169160009183916370a0823191602480820192602092909190829003018186803b1580156135ca57600080fd5b505afa1580156135de573d6000803e3d6000fd5b505050506040513d60208110156135f457600080fd5b505160408051600160e01b6323b872dd0281523360048201523060248201526044810186905290519192506001600160a01b038416916323b872dd916064808201926020929091908290030181600087803b15801561365257600080fd5b505af1158015613666573d6000803e3d6000fd5b505050506040513d602081101561367c57600080fd5b505060408051600160e01b6370a08231028152306004820152905182916001600160a01b038516916370a0823191602480820192602092909190829003018186803b1580156136ca57600080fd5b505afa1580156136de573d6000803e3d6000fd5b505050506040513d60208110156136f457600080fd5b505111611bc15760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1514905394d1915497d1905253115102604482015290519081900360640190fd5b6001600160a01b03166000908152606d6020526040902090565b6000818152606e60205260409020546001600160a01b0383811691161461251f57606f8054600181019091557f39f2babe526038520877fc7c33d81accf578af4a06c5fa6b0d038cae36e127110180546001600160a01b0384166001600160a01b031991821681179092556000838152606e60205260409020805490911690911790555050565b6000828201838110156137f357600080fd5b9392505050565b6000818152607360205260409020546001600160a01b031615611cf157600090815260736020526040902080546001600160a01b0319169055565b6067546000906001600160a01b031661385957506001600160a01b038116316114b0565b60675460408051600160e01b6370a082310281526001600160a01b038581166004830152915191909216916370a08231916024808301926020929190829003018186803b1580156138a957600080fd5b505afa1580156138bd573d6000803e3d6000fd5b505050506040513d60208110156138d357600080fd5b505190506114b0565b6138ed6138e761272d565b82613e2e565b60408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b600081613932816122b1565b6139795760408051600160e51b62461bcd02815260206004820152600d60248201526001609a1b6c12d15657d393d517d59053125102604482015290519081900360640190fd5b600061398484613740565b9050600042826001015403905060695481106139a457606a5493506139c5565b606954606a546139ba908363ffffffff613e0716565b816139c157fe5b0493505b60006078546139e1607754606a54613e0790919063ffffffff16565b816139e857fe5b049050808511156139fd578085039450613a02565b600094505b50505050919050565b606c54606b5411613a665760408051600160e51b62461bcd02815260206004820152600d60248201527f4c4f434b5f534f4c445f4f555400000000000000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b038216613ab95760408051600160e51b62461bcd02815260206004820152600f6024820152600160881b6e494e56414c49445f4144445245535302604482015290519081900360640190fd5b606a5460685460408051600160e01b630cb175e30281526001600160a01b03868116600483015260248201859052825160009586959094921692630cb175e3926044808301939192829003018186803b158015613b1557600080fd5b505afa158015613b29573d6000803e3d6000fd5b505050506040513d6040811015613b3f57600080fd5b50805160209091015190935091508080841115613b5e57506000613b63565b508281035b613b6c8161350e565b6000613b7787613740565b6001810154815491925090613bac57613b8f82614336565b613b9d88836000015461375a565b60695442016001830155613bc6565b606954613bc090829063ffffffff6137e116565b60018301555b8515613c3c5760685460408051600160e01b6336524663028152600481018990526024810188905290516001600160a01b039092169163365246639160448082019260009290919082900301818387803b158015613c2357600080fd5b505af1158015613c37573d6000803e3d6000fd5b505050505b60685460408051600160e01b63939d9f1f028152600481018690526001600160a01b038a811660248301529151919092169163939d9f1f91604480830192600092919082900301818387803b158015613c9457600080fd5b505af1158015613ca8573d6000803e3d6000fd5b5050606c546040519092506001600160a01b038b1691506000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050505050505050565b6001600160a01b038216613d445760408051600160e51b62461bcd02815260206004820152600f6024820152600160881b6e494e56414c49445f4144445245535302604482015290519081900360640190fd5b6000613d4f83613740565b905080600101548211613dac5760408051600160e51b62461bcd02815260206004820152601060248201527f414c52454144595f4f574e535f4b455900000000000000000000000000000000604482015290519081900360640190fd5b613db581614336565b613dc383826000015461375a565b6001810182905580546040516001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b600082613e165750600061157e565b82820282848281613e2357fe5b04146137f357600080fd5b801561251f576067546001600160a01b0316613e80576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015613e7a573d6000803e3d6000fd5b5061251f565b60675460408051600160e01b6370a082310281526001600160a01b0385811660048301529151919092169160009183916370a08231916024808301926020929190829003018186803b158015613ed557600080fd5b505afa158015613ee9573d6000803e3d6000fd5b505050506040513d6020811015613eff57600080fd5b505160408051600160e01b63a9059cbb0281526001600160a01b0387811660048301526024820187905291519293509084169163a9059cbb916044808201926020929091908290030181600087803b158015613f5a57600080fd5b505af1158015613f6e573d6000803e3d6000fd5b505050506040513d6020811015613f8457600080fd5b505060408051600160e01b6370a082310281526001600160a01b038681166004830152915183928516916370a08231916024808301926020929190829003018186803b158015613fd357600080fd5b505afa158015613fe7573d6000803e3d6000fd5b505050506040513d6020811015613ffd57600080fd5b5051116134055760408051600160e51b62461bcd02815260206004820152600f60248201526001608a1b6e1514905394d1915497d1905253115102604482015290519081900360640190fd5b600061405d846001600160a01b031661434b565b6140695750600161187b565b604051600160e11b630a85bd0102815233600482018181526001600160a01b03888116602485015260448401879052608060648501908152865160848601528651600095928a169463150b7a029490938c938b938b939260a4019060208501908083838e5b838110156140e65781810151838201526020016140ce565b50505050905090810190601f1680156141135780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561413557600080fd5b505af1158015614149573d6000803e3d6000fd5b505050506040513d602081101561415f57600080fd5b50516001600160e01b031916600160e11b630a85bd010214915050949350505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b600081516041146141e65750600061157e565b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561422c576000935050505061157e565b8060ff16601b1415801561424457508060ff16601c14155b15614255576000935050505061157e565b6040805160008152602080820180845289905260ff8416828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa1580156142ac573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b303b1590565b6001600160a01b0381166142da57600080fd5b6034546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603480546001600160a01b0319166001600160a01b0392909216919091179055565b8054611cf157606c8054600101908190559055565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106143925782800160ff198235161785556143bf565b828001600101855582156143bf579182015b828111156143bf5782358255916020019190600101906143a4565b506143cb9291506143cf565b5090565b61157091905b808211156143cb57600081556001016143d556fe436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564a165627a7a7230582031474d01281aa90a56dde5554eed5c93cdafcfbf9c58bfb981584096593435520029436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a65640000000000000000000000003ca206264762caf81a8f0a843bbb850987b41e16000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d4d61792032387468204c6f636b00000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003ca206264762caf81a8f0a843bbb850987b41e16000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d4d61792032387468204c6f636b00000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _owner (address): 0x3ca206264762caf81a8f0a843bbb850987b41e16
Arg [1] : _expirationDuration (uint256): 86400
Arg [2] : _tokenAddress (address): 0x0000000000000000000000000000000000000000
Arg [3] : _keyPrice (uint256): 0
Arg [4] : _maxNumberOfKeys (uint256): 115792089237316195423570985008687907853269984665640564039457584007913129639935
Arg [5] : _lockName (string): May 28th Lock
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000003ca206264762caf81a8f0a843bbb850987b41e16
Arg [1] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Arg [5] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [6] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [7] : 4d61792032387468204c6f636b00000000000000000000000000000000000000
Deployed ByteCode Sourcemap
66845:1056:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;44449:21:0;;;-1:-1:-1;;;;;44449:21:0;;;;;;;;;;;;-1:-1:-1;;;;;44449:21:0;;;;;;;;;;;;;;11588:135;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11588:135:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11588:135:0;-1:-1:-1;;;;;;11588:135:0;;:::i;:::-;;;;;;;;;;;;;;;;;;26768:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;26768:23:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;26768:23:0;;:::i;:::-;;;;-1:-1:-1;;;;;26768:23:0;;;;;;;;;;;;;;42243:94;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42243:94:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;42243:94:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34925:138;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34925:138:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;34925:138:0;;:::i;33955:311::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;33955:311:0;;;;;;;;:::i;:::-;;53428:41;;8:9:-1;5:2;;;30:1;27;20:12;5:2;53428:41:0;;;:::i;:::-;;;;;;;;;;;;;;;;53385:38;;8:9:-1;5:2;;;30:1;27;20:12;5:2;53385:38:0;;;:::i;22504:29::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;22504:29:0;;;:::i;29058:879::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;29058:879:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;29058:879:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;29058:879:0;;;;;;;;;;;;;;;;;22879:20;;8:9:-1;5:2;;;30:1;27;20:12;5:2;22879:20:0;;;:::i;22721:30::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;22721:30:0;;;:::i;13422:147::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;13422:147:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;13422:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;13422:147:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;13422:147:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;13422:147:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;13422:147:0;;-1:-1:-1;13422:147:0;;-1:-1:-1;;;;;13422:147:0:i;:::-;;;;-1:-1:-1;;;;;;13422:147:0;;;;;;;;;;;;;;25099:104;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25099:104:0;;;:::i;24762:213::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24762:213:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;24762:213:0;;:::i;54007:85::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54007:85:0;;;:::i;60759:1750::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;60759:1750:0;;;;;;;;;;;;;;;;;:::i;42996:134::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42996:134:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;42996:134:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;42996:134:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42996:134:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;42996:134:0;;-1:-1:-1;42996:134:0;-1:-1:-1;42996:134:0;:::i;55040:491::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;55040:491:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;55040:491:0;;;;;;;:::i;23067:28::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;23067:28:0;;;:::i;23860:268::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;23860:268:0;;;:::i;64065:463::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64065:463:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;64065:463:0;;;;;;;:::i;17668:19::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;17668:19:0;;;:::i;62862:174::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;62862:174:0;;;;;;;;;;;;;;;;;:::i;38910:820::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38910:820:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;38910:820:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;38910:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;38910:820:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;38910:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;38910:820:0;;;;;;;;-1:-1:-1;38910:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;38910:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;38910:820:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;38910:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;38910:820:0;;;;;;;;-1:-1:-1;38910:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;38910:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;38910:820:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;38910:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;38910:820:0;;;;;;;;-1:-1:-1;38910:820:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;38910:820:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;38910:820:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;38910:820:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;38910:820:0;;-1:-1:-1;38910:820:0;;-1:-1:-1;;;;;38910:820:0:i;53533:47::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;53533:47:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;53533:47:0;-1:-1:-1;;;;;53533:47:0;;:::i;39736:516::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;39736:516:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;39736:516:0;;:::i;55817:163::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;55817:163:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;55817:163:0;-1:-1:-1;;;;;55817:163:0;;:::i;42019:121::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42019:121:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;42019:121:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;42019:121:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42019:121:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;42019:121:0;;-1:-1:-1;42019:121:0;-1:-1:-1;42019:121:0;:::i;40258:457::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40258:457:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;40258:457:0;-1:-1:-1;;;;;40258:457:0;;:::i;54884:84::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54884:84:0;;;:::i;30923:150::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30923:150:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30923:150:0;;:::i;28359:171::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28359:171:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28359:171:0;-1:-1:-1;;;;;28359:171:0;;:::i;28094:197::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28094:197:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28094:197:0;-1:-1:-1;;;;;28094:197:0;;:::i;47434:209::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;47434:209:0;;;;;;;;;;:::i;9378:140::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9378:140:0;;;:::i;24308:342::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24308:342:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;24308:342:0;;:::i;22973:27::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;22973:27:0;;;:::i;42419:167::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42419:167:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;42419:167:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;42419:167:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42419:167:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;42419:167:0;;-1:-1:-1;42419:167:0;-1:-1:-1;42419:167:0;:::i;37738:257::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37738:257:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;37738:257:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;37738:257:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;37738:257:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;37738:257:0;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;37738:257:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;37738:257:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;37738:257:0;;-1:-1:-1;37738:257:0;-1:-1:-1;37738:257:0;:::i;64793:727::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64793:727:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;64793:727:0;-1:-1:-1;;;;;64793:727:0;;:::i;56093:456::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;56093:456:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;56093:456:0;;;;;;;;;;:::i;8665:79::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8665:79:0;;;:::i;9000:92::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9000:92:0;;;:::i;60531:36::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60531:36:0;;;:::i;30688:104::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30688:104:0;;;:::i;42691:215::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42691:215:0;;;:::i;28647:173::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28647:173:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28647:173:0;-1:-1:-1;;;;;28647:173:0;;:::i;30015:155::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30015:155:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30015:155:0;;;;;;-1:-1:-1;;;;;30015:155:0;;:::i;37020:163::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37020:163:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;37020:163:0;;;;;;;;:::i;14774:27::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;14774:27:0;;;:::i;27665:266::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;27665:266:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;27665:266:0;-1:-1:-1;;;;;27665:266:0;;:::i;34554:268::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34554:268:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;34554:268:0;;;;;;;;;;:::i;18338:501::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;18338:501:0;;;:::i;30328:200::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30328:200:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30328:200:0;-1:-1:-1;;;;;30328:200:0;;:::i;63608:382::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;63608:382:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;63608:382:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;63608:382:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;63608:382:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;63608:382:0;;-1:-1:-1;63608:382:0;;-1:-1:-1;;;;;63608:382:0:i;54337:401::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54337:401:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;54337:401:0;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;54337:401:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;54337:401:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;54337:401:0;;-1:-1:-1;54337:401:0;-1:-1:-1;54337:401:0;:::i;18076:121::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;18076:121:0;;;:::i;8452:145::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8452:145:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;8452:145:0;-1:-1:-1;;;;;8452:145:0;;:::i;43471:445::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43471:445:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43471:445:0;;:::i;67805:93::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;67805:93:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;60572:40;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60572:40:0;;;:::i;35380:173::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;35380:173:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;35380:173:0;;;;;;;;;;:::i;9695:109::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9695:109:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9695:109:0;-1:-1:-1;;;;;9695:109:0;;:::i;47070:154::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;47070:154:0;-1:-1:-1;;;;;47070:154:0;;:::i;37337:241::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37337:241:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;37337:241:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;37337:241:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;37337:241:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;37337:241:0;;-1:-1:-1;37337:241:0;-1:-1:-1;37337:241:0;;:::i;11588:135::-;-1:-1:-1;;;;;;11682:33:0;;11658:4;11682:33;;;;;;;;;;;;;11588:135;;;;:::o;26768:23::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;26768:23:0;;-1:-1:-1;26768:23:0;:::o;42243:94::-;42323:8;42316:15;;;;;;;;-1:-1:-1;;42316:15:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42291:13;;42316:15;;42323:8;;42316:15;;42323:8;42316:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;42243:94;;:::o;34925:138::-;35009:7;35035:22;35048:8;35035:12;:22::i;:::-;35028:29;34925:138;-1:-1:-1;;34925:138:0:o;33955:311::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;34093:8;33568:32;33579:8;33589:10;33568;:32::i;:::-;:78;;;;33613:33;33625:8;33635:10;33613:11;:33::i;:::-;33568:138;;;;33659:47;33676:17;33684:8;33676:7;:17::i;:::-;33695:10;33659:16;:47::i;:::-;33552:192;;;;;-1:-1:-1;;;;;33552:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;34121:10;-1:-1:-1;;;;;34121:23:0;;;;34113:48;;;;;-1:-1:-1;;;;;34113:48:0;;;;;;;;;;;;-1:-1:-1;;;;;34113:48:0;;;;;;;;;;;;;;;34170:18;;;;:8;:18;;;;;:30;;-1:-1:-1;;;;;;34170:30:0;-1:-1:-1;;;;;34170:30:0;;;;;;;;:18;;34221:17;34170:18;34221:7;:17::i;:::-;-1:-1:-1;;;;;34212:48:0;;;;;;;;;;;17969:1;33955:311;;:::o;53428:41::-;;;;:::o;53385:38::-;;;;:::o;22504:29::-;;;-1:-1:-1;;;;;22504:29:0;;:::o;29058:879::-;29183:6;:13;29147:16;;29175:49;;;;;-1:-1:-1;;;;;29175:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;29362:6;:13;29247:9;;29282:16;;;;29231:13;;29337:22;;;:38;29333:202;;;-1:-1:-1;29403:6:0;:13;29436:27;;;;-1:-1:-1;29333:202:0;;;-1:-1:-1;29504:22:0;;;29333:202;29621:29;29667:8;29653:23;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;29653:23:0;-1:-1:-1;29621:55:0;-1:-1:-1;29683:14:0;29794:11;29780:124;29811:14;29807:1;:18;29780:124;;;29867:6;29874:1;29867:9;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;29867:9:0;29841:12;29854:9;29841:23;;;;;;;;-1:-1:-1;;;;;29841:35:0;;;:23;;;;;;;;;;;:35;29885:11;;;;;29827:3;29780:124;;;-1:-1:-1;29919:12:0;;29058:879;-1:-1:-1;;;;;;;29058:879:0:o;22879:20::-;;;;:::o;22721:30::-;;;;:::o;13422:147::-;-1:-1:-1;;;;;13422:147:0;;;;;;;:::o;25099:104::-;25181:16;;25099:104;:::o;24762:213::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;24887:8;;;24902:20;;;;24934:35;;;;;;;;;;;;;;;;;;;;;;;;;17969:1;24762:213;:::o;54007:85::-;54058:28;54075:10;54058:16;:28::i;:::-;54007:85::o;60759:1750::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;60910:5;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;60945:8;33568:32;33579:8;33589:10;33568;:32::i;:::-;:78;;;;33613:33;33625:8;33635:10;33613:11;:33::i;:::-;33568:138;;;;33659:47;33676:17;33684:8;33676:7;:17::i;33659:47::-;33552:192;;;;;-1:-1:-1;;;;;33552:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;60973:24:0;;60965:52;;;;;-1:-1:-1;;;;;60965:52:0;;;;;;;;;;;;-1:-1:-1;;;;;60965:52:0;;;;;;;;;;;;;;;61024:37;61039:21;61054:5;61039:14;:21::i;:::-;61024:14;:37::i;:::-;61070:19;61092:17;61103:5;61092:10;:17::i;:::-;61070:39;;61116:17;61136:22;61147:10;61136;:22::i;:::-;61193:25;;;;61231:13;;61116:42;;-1:-1:-1;61193:25:0;61227:120;;61276:15;;61260:31;;;61300:39;;61313:10;;61300:12;:39::i;:::-;61381:15;61359:18;:37;61355:764;;61662:27;;;;;61634:25;;;:55;61714:15;;61698:31;;61738:34;61751:10;61763:8;61738:12;:34::i;:::-;61355:764;;;62032:37;;;;:79;;62095:15;62074:36;;62032:79;:41;:79;:::i;:::-;62004:25;;;:107;61355:764;62217:15;62187:27;;;:45;62331:1;62313:19;;62378:24;62393:8;62378:14;:24::i;:::-;62488:8;62469:10;-1:-1:-1;;;;;62438:65:0;62455:5;-1:-1:-1;;;;;62438:65:0;;;;;;;;;;;33751:1;;;27197;17969;60759:1750;;;:::o;42996:134::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;43096:28;:12;43111:13;;43096:28;:::i;:::-;;42996:134;;:::o;55040:491::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;55193:30;55185:55;;;;;-1:-1:-1;;;;;55185:55:0;;;;;;;;;;;;-1:-1:-1;;;;;55185:55:0;;;;;;;;;;;;;;;55283:22;;55314:24;;55254:157;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55418:22;:48;;;;55473:24;:52;55040:491::o;23067:28::-;;;;:::o;23860:268::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;23919:12;23934:26;23954:4;23934:11;:26::i;:::-;23919:41;;23985:1;23975:7;:11;23967:40;;;;;-1:-1:-1;;;;;23967:40:0;;;;;;;;;;;;-1:-1:-1;;;;;23967:40:0;;;;;;;;;;;;;;;24104:18;24114:7;24104:9;:18::i;:::-;8898:1;23860:268::o;64065:463::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;64212:28;64204:53;;;;;-1:-1:-1;;;;;64204:53:0;;;;;;;;;;;;-1:-1:-1;;;;;64204:53:0;;;;;;;;;;;;;;;64296:20;;64325:22;;64269:147;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;64423:20;:44;;;;64474:22;:48;64065:463::o;17668:19::-;;;-1:-1:-1;;;17668:19:0;;;;;:::o;62862:174::-;62988:42;63005:5;63012:3;63017:8;62988:42;;;;;;;;;;;;:16;:42::i;38910:820::-;39057:33;39102:16;39127:2;39102:28;;39137:16;39162:2;39137:28;;39172:16;39197:2;39172:28;;39207:16;39232:2;39207:28;;39242:18;39313:3;:10;39300:3;:10;39287:3;:10;39274:3;:10;:23;:36;:49;39263:61;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;39263:61:0;87:34:-1;135:17;;-1:-1;39263:61:0;-1:-1:-1;39242:82:0;-1:-1:-1;39242:82:0;39370:6;;39404:69;39420:3;:10;39416:1;:14;39404:69;;;39459:3;39463:1;39459:6;;;;;;;;;;;;;;;;39446:5;39452:3;;;;;;39446:10;;;;;;;;;;;:19;-1:-1:-1;;;;;39446:19:0;;;;;;;;-1:-1:-1;39432:3:0;;39404:69;;;-1:-1:-1;39488:1:0;39479:69;39495:3;:10;39491:1;:14;39479:69;;;39534:3;39538:1;39534:6;;;;;;;;;;;;;;;;39521:5;39527:3;;;;;;39521:10;;;;;;;;;;;:19;-1:-1:-1;;;;;39521:19:0;;;;;;;;-1:-1:-1;39507:3:0;;39479:69;;;-1:-1:-1;39563:1:0;39554:69;39570:3;:10;39566:1;:14;39554:69;;;39609:3;39613:1;39609:6;;;;;;;;;;;;;;;;39596:5;39602:3;;;;;;39596:10;;;;;;;;;;;:19;-1:-1:-1;;;;;39596:19:0;;;;;;;;-1:-1:-1;39582:3:0;;39554:69;;;-1:-1:-1;39638:1:0;39629:69;39645:3;:10;39641:1;:14;39629:69;;;39684:3;39688:1;39684:6;;;;;;;;;;;;;;;;39671:5;39677:3;;;;;;39671:10;;;;;;;;;;;:19;-1:-1:-1;;;;;39671:19:0;;;;;;;;-1:-1:-1;39657:3:0;;39629:69;;;-1:-1:-1;39718:5:0;;38910:820;-1:-1:-1;;;;;;;;;;;38910:820:0:o;53533:47::-;;;;;;;;;;;;;:::o;39736:516::-;39804:27;39926:2;39939:7;39935:40;;-1:-1:-1;;39957:10:0;;;;;;;;;;;;-1:-1:-1;;;;;39957:10:0;;;;;;39935:40;39990:2;39981:6;40014:53;40021:6;;40014:53;;40038:5;;40057:2;40052:7;;;;40014:53;;;40073:17;40103:3;40093:14;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;40093:14:0;87:34:-1;135:17;;-1:-1;40093:14:0;-1:-1:-1;40073:34:0;-1:-1:-1;;;40123:7:0;;40137:84;40144:6;;40137:84;;40193:2;40189:1;:6;40184:2;:11;40173:24;;40161:4;40166:3;;;;;;;40161:9;;;;;;;;;;;:36;-1:-1:-1;;;;;40161:36:0;;;;;;;;-1:-1:-1;40211:2:0;40206:7;;;;40137:84;;;-1:-1:-1;40241:4:0;39736:516;-1:-1:-1;;;;;39736:516:0:o;55817:163::-;55912:11;55942:32;55967:6;55942:24;:32::i;42019:121::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;42114:20;:8;42125:9;;42114:20;:::i;40258:457::-;40405:42;;;;;;;;;;;;;;;;40473:13;;40483:2;40473:13;;;40334;40473;;;;;;-1:-1:-1;;;;;40383:14:0;;;40405:42;40334:13;;40473;;;21:6:-1;;104:10;40473:13:0;87:34:-1;135:17;;-1:-1;40473:13:0;40454:32;;-1:-1:-1;;;;;40493:3:0;40497:1;40493:6;;;;;;;;;;;:12;-1:-1:-1;;;;;40493:12:0;;;;;;;;;-1:-1:-1;;;;;40512:3:0;40516:1;40512:6;;;;;;;;;;;:12;-1:-1:-1;;;;;40512:12:0;;;;;;;;-1:-1:-1;40536:6:0;40531:154;40552:2;40548:1;:6;40531:154;;;40583:8;40615:1;40598:5;40604:1;40608:2;40604:6;40598:13;;;;;;;;;;-1:-1:-1;;;;;40598:18:0;;;;40592:25;;40583:35;;;;;;;;;;;;;;;;;;40570:3;40576:1;40578;40576:3;40574:1;:5;40570:10;;;;;;;;;;;:48;-1:-1:-1;;;;;40570:48:0;;;;;;;;;40640:8;40655:5;40661:1;40665:2;40661:6;40655:13;;;;;;;;;;40671:4;40655:20;;;40649:27;;40640:37;;;;;;;;;;;;;;;;;;40627:3;40633:1;40635;40633:3;40631:1;:5;40627:10;;;;;;;;;;;:50;-1:-1:-1;;;;;40627:50:0;;;;;;;;-1:-1:-1;40556:3:0;;40531:154;;;-1:-1:-1;40705:3:0;40258:457;-1:-1:-1;;;;40258:457:0:o;54884:84::-;54949:10;54933:27;;;;:15;:27;;;;;:29;;;;;;54884:84::o;30923:150::-;31017:7;27311:24;;;:14;:24;;;;;;30993:8;;-1:-1:-1;;;;;27311:24:0;27295:76;;;;;-1:-1:-1;;;;;27295:76:0;;;;;;;;;;;;-1:-1:-1;;;;;27295:76:0;;;;;;;;;;;;;;;-1:-1:-1;;31043:24:0;;;;:14;:24;;;;;;-1:-1:-1;;;;;31043:24:0;;30923:150::o;28359:171::-;-1:-1:-1;;;;;28468:18:0;28445:4;28468:18;;;:10;:18;;;;;:38;;;28509:15;-1:-1:-1;;28359:171:0:o;28094:197::-;28177:4;-1:-1:-1;;;;;28201:20:0;;28193:48;;;;;-1:-1:-1;;;;;28193:48:0;;;;;;;;;;;;-1:-1:-1;;;;;28193:48:0;;;;;;;;;;;;;;;28255:22;28270:6;28255:14;:22::i;:::-;:30;;28284:1;28255:30;;;28280:1;28255:30;28248:37;;;28094:197;-1:-1:-1;;28094:197:0:o;47434:209::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;47574:9;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;47602:35;47615:10;47627:9;47602:12;:35::i;9378:140::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;9461:6;;9440:40;;9477:1;;-1:-1:-1;;;;;9461:6:0;;9440:40;;9477:1;;9440:40;9491:6;:19;;-1:-1:-1;;;;;;9491:19:0;;;9378:140::o;24308:342::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;24404:1;24394:7;:11;24386:41;;;;;-1:-1:-1;;;;;24386:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;24434:12;24449:26;24469:4;24449:11;:26::i;:::-;24434:41;;24501:7;24490;:18;;24482:47;;;;;-1:-1:-1;;;;;24482:47:0;;;;;;;;;;;;-1:-1:-1;;;;;24482:47:0;;;;;;;;;;;;;;;24626:18;24636:7;24626:9;:18::i;:::-;8898:1;24308:342;:::o;22973:27::-;;;;:::o;42419:167::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;42518:24;:10;42531:11;;42518:24;:::i;:::-;;42554:26;42568:11;;42554:26;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;;74:27;42554:26:0;;137:4:-1;117:14;;;-1:-1;;113:30;157:16;;;42554:26:0;;;;-1:-1:-1;42554:26:0;;-1:-1:-1;;;;42554:26:0;42419:167;;:::o;37738:257::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;37881:6;37877:113;37893:22;;;37877:113;;;37931:51;37941:11;;37953:1;37941:14;;;;;;;;;;;;;-1:-1:-1;;;;;37941:14:0;37957:21;;37979:1;37957:24;;;;;;;;;;;;;37931:9;:51::i;:::-;37917:3;;37877:113;;;;37738:257;;;;:::o;64793:727::-;64899:4;64877:6;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;64915:15;64933:18;64944:6;64933:10;:18::i;:::-;64915:36;;65051:18;65098:15;65072:3;:23;;;:41;65051:62;;65120:8;65155:18;;65138:13;:35;65135:312;;-1:-1:-1;65276:8:0;;65135:312;;;65421:18;;65391:8;;:27;;65404:13;65391:27;:12;:27;:::i;:::-;:48;;;;;;65385:54;;65135:312;65492:22;;65468:20;;65460:29;;:3;;:29;:7;:29;:::i;:::-;:54;;;;;;;64793:727;-1:-1:-1;;;;;;64793:727:0:o;56093:456::-;-1:-1:-1;;;;;56416:26:0;;;56212:20;56416:26;;;:15;:26;;;;;;;;;;56269:267;;56350:4;56269:267;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;6:49;;56269:267:0;;;;;;56251:292;;;;;;56093:456::o;8665:79::-;8730:6;;-1:-1:-1;;;;;8730:6:0;8665:79;:::o;9000:92::-;9078:6;;-1:-1:-1;;;;;9078:6:0;9064:10;:20;;9000:92::o;60531:36::-;;;;:::o;30688:104::-;30773:6;:13;30688:104;:::o;42691:215::-;42775:10;42769:24;42741:13;;42769:24;-1:-1:-1;;42769:24:0;;;;;;;;;;;42766:135;;42816:14;;;;;;;;;-1:-1:-1;;;;;42816:14:0;-1:-1:-1;;;;;42816:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42816:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;42816:37:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;42816:37:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;42816:37:0;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;-1:-1;42816:37:0;;-1:-1:-1;42809:44:0;;-1:-1:-1;;;;42809:44:0;42766:135;42883:10;42876:17;;;;;;;;;;;;;-1:-1:-1;;42876:17:0;;;;;;;;;;;;;;;;;;;;;;;;;;;42883:10;42876:17;;42883:10;42876:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28647:173;28763:4;28739:8;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;28786:20:0;;;;;:10;:20;;;;;:28;;28647:173::o;30015:155::-;30107:4;30130:24;;;:14;:24;;;;;;;-1:-1:-1;;;;;30130:34:0;;;:24;;:34;;30015:155::o;37020:163::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;37134:43;37144:10;37156:20;37134:9;:43::i;14774:27::-;;;-1:-1:-1;;;;;14774:27:0;;:::o;27665:266::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;27757:6;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;27793:18:0;;27775:15;27793:18;;;:10;:18;;;;;;;;;27844:15;27818:23;;;:41;27913:11;;27903:22;;;;;;;27793:18;;27903:22;;;;;;;;;27197:1;8898;27665:266;:::o;34554:268::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;34669:17:0;;34676:10;34669:17;;34661:42;;;;;-1:-1:-1;;;;;34661:42:0;;;;;;;;;;;;-1:-1:-1;;;;;34661:42:0;;;;;;;;;;;;;;;34734:10;34710:35;;;;:23;:35;;;;;;;;-1:-1:-1;;;;;34710:40:0;;;;;;;;;;;;:52;;-1:-1:-1;;34710:52:0;;;;;;;;;;34774:42;;;;;;;34710:40;;34734:10;34774:42;;;;;;;;;;;34554:268;;:::o;18338:501::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;18408:7;;-1:-1:-1;;;18408:7:0;;;;:16;18400:42;;;;;-1:-1:-1;;;;;18400:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;18456;;;18472:4;18464:21;18456:42;;;;18487:10;;18456:42;;;;;;;;;;18577:49;18587:10;18599:26;18619:4;18599:11;:26::i;:::-;18577:9;:49::i;:::-;18646:10;18633:24;30328:200;-1:-1:-1;;;;;26938:18:0;;30451:14;26938:18;;;:10;:18;;;;;:38;;;30429:6;;26922:88;;;;;-1:-1:-1;;;;;26922:88:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;30484:18:0;;;;;:10;:18;;;;;:38;;;;30328:200::o;63608:382::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;63792:8;33568:32;33579:8;33589:10;33568;:32::i;:::-;:78;;;;33613:33;33625:8;33635:10;33613:11;:33::i;:::-;33568:138;;;;33659:47;33676:17;33684:8;33676:7;:17::i;33659:47::-;33552:192;;;;;-1:-1:-1;;;;;33552:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;63819:17;63827:8;63819:7;:17::i;:::-;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;63848:34;63861:5;63868:3;63873:8;63848:12;:34::i;:::-;63897:51;63920:5;63927:3;63932:8;63942:5;63897:22;:51::i;:::-;63889:93;;;;;-1:-1:-1;;;;;63889:93:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;33751:1;17969;63608:382;;;;:::o;54337:401::-;54624:9;-1:-1:-1;;;;;54461:172:0;:159;54485:105;54526:53;54557:9;54568:10;54526:30;:53::i;:::-;54485:28;:105::i;:::-;54601:10;;54461:159;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;54461:13:0;;-1:-1:-1;;;54461:159:0:i;:::-;-1:-1:-1;;;;;54461:172:0;;54445:216;;;;;-1:-1:-1;;;;;54445:216:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;54670:26:0;;;;;;:15;:26;;;;;:28;;;;;;54705:27;54686:9;54705:16;:27::i;18076:121::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;18160:9;;;;;;;18176:7;:15;;-1:-1:-1;;18176:15:0;;;18076:121::o;8452:145::-;6947:12;;;;;;;;:31;;;6963:15;:13;:15::i;:::-;6947:47;;;-1:-1:-1;6983:11:0;;;;6982:12;6947:47;6939:106;;;;-1:-1:-1;;;;;6939:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7077:12;;;;-1:-1:-1;;7096:19:0;;;;-1:-1:-1;;7122:18:0;;;;;;8518:6;:15;;-1:-1:-1;;;;;;8518:15:0;-1:-1:-1;;;;;8518:15:0;;;;;;;;;;;8549:40;;7077:12;;;;;;;8582:6;;;-1:-1:-1;;8549:40:0;;-1:-1:-1;;8549:40:0;7159:12;:30;;;;;;;-1:-1:-1;;7159:30:0;;;;;;;;;-1:-1:-1;8452:145:0:o;43471:445::-;27347:1;27311:24;;;:14;:24;;;;;;43570:13;;43547:8;;-1:-1:-1;;;;;27311:24:0;27295:76;;;;;-1:-1:-1;;;;;27295:76:0;;;;;;;;;;;;-1:-1:-1;;;;;27295:76:0;;;;;;;;;;;;;;;43628:12;43622:26;43595:17;;43622:26;-1:-1:-1;;43622:26:0;;;;;;;;;;;43619:138;;43670:14;;;;;;;;;-1:-1:-1;;;;;43670:14:0;-1:-1:-1;;;;;43670:36:0;;:38;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43670:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43670:38:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;43670:38:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;43670:38:0;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;-1:-1;43670:38:0;;-1:-1:-1;43619:138:0;;-1:-1:-1;;;;43619:138:0;;43737:12;43731:18;;;;;;;;;;;;;-1:-1:-1;;43731:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;43737:12;43731:18;;43737:12;43731:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43619:138;43772;43802:3;43814:38;43846:4;43814:23;:38::i;:::-;43772:138;;;;;;;;;;;;;-1:-1:-1;;;;;43772:138:0;;;43873:30;43894:8;43873:20;:30::i;:::-;43772:21;:138::i;67805:93::-;67891:1;67805:93;:::o;60572:40::-;;;;:::o;35380:173::-;-1:-1:-1;;;;;35505:31:0;;;35482:4;35505:31;;;:23;:31;;;;;;;;:42;;;;;;;;;;;;;;;35380:173::o;9695:109::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;9768:28;9787:8;9768:18;:28::i;47070:154::-;17935:7;;-1:-1:-1;;;17935:7:0;;;;17927:35;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;-1:-1:-1;;;;;17927:35:0;;;;;;;;;;;;;;;47182:36;47195:10;47215:1;47182:12;:36::i;37337:241::-;8877:9;:7;:9::i;:::-;8869:18;;;;;;37468:6;37464:109;37480:22;;;37464:109;;;37518:47;37528:11;;37540:1;37528:14;;;;;;;;;;;;;-1:-1:-1;;;;;37528:14:0;37544:20;37518:9;:47::i;:::-;37504:3;;37464:109;;;;37337:241;;;:::o;35970:251::-;36055:7;36102:18;;;:8;:18;;;;;;-1:-1:-1;;;;;36102:18:0;36135:31;36127:57;;;;;-1:-1:-1;;;;;36127:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;35646:150;35740:4;35763:18;;;:8;:18;;;;;;;-1:-1:-1;;;;;35763:27:0;;;:18;;:27;;35646:150::o;56659:594::-;56733:15;56751:21;56762:9;56751:10;:21::i;:::-;56733:39;;56781:11;56795:35;56820:9;56795:24;:35::i;:::-;56854:11;;56844:53;;;;;;;;56781:49;;-1:-1:-1;56878:10:0;;-1:-1:-1;;;;;56844:53:0;;;56854:11;56844:53;;;;;;;;;;57096:15;57070:23;;;:41;57124:10;;57120:128;;57211:29;57221:10;57233:6;57211:9;:29::i;15335:684::-;15404:10;;15401:613;;15428:12;;-1:-1:-1;;;;;15428:12:0;15425:582;;15488:6;15475:9;:19;;15467:48;;;;;-1:-1:-1;;;;;15467:48:0;;;;;;;;;;;;-1:-1:-1;;;;;15467:48:0;;;;;;;;;;;;;;;15425:582;;;15564:12;;15609:30;;;-1:-1:-1;;;;;15609:30:0;;15633:4;15609:30;;;;;;-1:-1:-1;;;;;15564:12:0;;;;15542;;15564;;15609:15;;:30;;;;;;;;;;;;;;;15564:12;15609:30;;;5:2:-1;;;;30:1;27;20:12;5:2;15609:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;15609:30:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;15609:30:0;15650:53;;;-1:-1:-1;;;;;15650:53:0;;15669:10;15650:53;;;;15689:4;15650:53;;;;;;;;;;;;15609:30;;-1:-1:-1;;;;;;15650:18:0;;;;;:53;;;;;15609:30;;15650:53;;;;;;;;-1:-1:-1;15650:18:0;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;15650:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;15650:53:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;15931:30:0;;;-1:-1:-1;;;;;15931:30:0;;15955:4;15931:30;;;;;;15964:13;;-1:-1:-1;;;;;15931:15:0;;;;;:30;;;;;15650:53;;15931:30;;;;;;;;:15;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;15931:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;15931:30:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;15931:30:0;:46;15923:74;;;;;-1:-1:-1;;;;;15923:74:0;;;;;;;;;;;;-1:-1:-1;;;;;15923:74:0;;;;;;;;;;;;;;32038:128;-1:-1:-1;;;;;32142:18:0;32112:11;32142:18;;;:10;:18;;;;;;32038:128::o;31660:308::-;31751:24;;;;:14;:24;;;;;;-1:-1:-1;;;;;31751:34:0;;;:24;;:34;31747:216;;31847:6;27:10:-1;;39:1;23:18;;45:23;;;31847:19:0;;;;-1:-1:-1;;;;;31847:19:0;;-1:-1:-1;;;;;;31847:19:0;;;;;;;;-1:-1:-1;31922:24:0;;;:14;31847:19;31922:24;;;;:33;;;;;;;;;;31660:308;;:::o;46033:150::-;46091:7;46123:5;;;46147:6;;;;46139:15;;;;;;46174:1;46033:150;-1:-1:-1;;;46033:150:0:o;36371:162::-;36476:1;36446:18;;;:8;:18;;;;;;-1:-1:-1;;;;;36446:18:0;:32;36442:86;;36518:1;36489:18;;;:8;:18;;;;;:31;;-1:-1:-1;;;;;;36489:31:0;;;36371:162::o;16898:239::-;16994:12;;16975:4;;-1:-1:-1;;;;;16994:12:0;16991:141;;-1:-1:-1;;;;;;17038:16:0;;;17031:23;;16991:141;17091:12;;17084:40;;;-1:-1:-1;;;;;17084:40:0;;-1:-1:-1;;;;;17084:40:0;;;;;;;;;17091:12;;;;;17084:30;;:40;;;;;;;;;;;;;;17091:12;17084:40;;;5:2:-1;;;;30:1;27;20:12;5:2;17084:40:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;17084:40:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;17084:40:0;;-1:-1:-1;17077:47:0;;25384:140;25440:35;25450:15;:13;:15::i;:::-;25467:7;25440:9;:35::i;:::-;25487:31;;;;;;;;25498:10;;25487:31;;;;;;;;;;25384:140;:::o;57455:845::-;57572:11;57550:6;27144:22;27159:6;27144:14;:22::i;:::-;27128:62;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;-1:-1:-1;;;;;27128:62:0;;;;;;;;;;;;;;;57595:15;57613:18;57624:6;57613:10;:18::i;:::-;57595:36;;57731:18;57778:15;57752:3;:23;;;:41;57731:62;;57820:18;;57803:13;:35;57800:232;;57858:8;;57849:17;;57800:232;;;58006:18;;57976:8;;:27;;57989:13;57976:27;:12;:27;:::i;:::-;:48;;;;;;57967:57;;57800:232;58038:12;58092:24;;58053:36;58066:22;;58053:8;;:12;;:36;;;;:::i;:::-;:63;;;;;;58038:78;;58136:7;58127:6;:16;58123:172;;;58247:7;58237:17;;;;58123:172;;;58286:1;58277:10;;58123:172;27197:1;;;57455:845;;;;:::o;48159:1778::-;23214:16;;23196:15;;:34;23188:60;;;;;-1:-1:-1;;;;;23188:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;48327:24:0;;48319:52;;;;;-1:-1:-1;;;;;48319:52:0;;;;;;;;;;;;-1:-1:-1;;;;;48319:52:0;;;;;;;;;;;;;;;48520:8;;48556:14;;:72;;;-1:-1:-1;;;;;48556:72:0;;-1:-1:-1;;;;;48556:72:0;;;;;;;;;;;;;;;48458:13;;;;48520:8;;48556:14;;;:42;;:72;;;;;;;;;;;;:14;:72;;;5:2:-1;;;;30:1;27;20:12;5:2;48556:72:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;48556:72:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;48556:72:0;;;;;;;;;-1:-1:-1;48556:72:0;-1:-1:-1;48651:16:0;48678:27;;;48674:239;;;-1:-1:-1;48727:1:0;48674:239;;;-1:-1:-1;48878:27:0;;;48674:239;48997:24;49012:8;48997:14;:24::i;:::-;49053:17;49073:22;49084:10;49073;:22::i;:::-;49128:25;;;;49164:13;;49053:42;;-1:-1:-1;49128:25:0;49160:475;;49193:24;49211:5;49193:17;:24::i;:::-;49226:39;49239:10;49251:5;:13;;;49226:12;:39::i;:::-;49453:18;;49435:15;:36;49407:25;;;:64;49160:475;;;49608:18;;49585:42;;:18;;:42;:22;:42;:::i;:::-;49557:25;;;:70;49160:475;49647:12;;49643:90;;49670:14;;:55;;;-1:-1:-1;;;;;49670:55:0;;;;;;;;;;;;;;;;-1:-1:-1;;;;;49670:14:0;;;;:37;;:55;;;;;:14;;:55;;;;;;;;:14;;:55;;;5:2:-1;;;;30:1;27;20:12;5:2;49670:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;49670:55:0;;;;49643:90;49741:14;;:53;;;-1:-1:-1;;;;;49741:53:0;;;;;;;;-1:-1:-1;;;;;49741:53:0;;;;;;;;;:14;;;;;:32;;:53;;;;;:14;;:53;;;;;;;:14;;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;49741:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;49908:16:0;;49830:101;;49908:16;;-1:-1:-1;;;;;;49830:101:0;;;-1:-1:-1;49855:1:0;;49830:101;;49855:1;;49830:101;23255:1;;;;;;48159:1778;;:::o;38050:560::-;-1:-1:-1;;;;;38157:24:0;;38149:52;;;;;-1:-1:-1;;;;;38149:52:0;;;;;;;;;;;;-1:-1:-1;;;;;38149:52:0;;;;;;;;;;;;;;;38210:17;38230:22;38241:10;38230;:22::i;:::-;38210:42;;38290:5;:25;;;38267:20;:48;38259:77;;;;;-1:-1:-1;;;;;38259:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;38345:24;38363:5;38345:17;:24::i;:::-;38376:39;38389:10;38401:5;:13;;;38376:12;:39::i;:::-;38422:25;;;:48;;;38584:13;;38506:98;;-1:-1:-1;;;;;38506:98:0;;;38584:13;;38506:98;;38584:13;;38506:98;38050:560;;;:::o;44786:433::-;44844:7;45088:6;45084:47;;-1:-1:-1;45118:1:0;45111:8;;45084:47;45155:5;;;45159:1;45155;:5;:1;45179:5;;;;;:10;45171:19;;;;;16177:645;16260:11;;16257:560;;16285:12;;-1:-1:-1;;;;;16285:12:0;16282:528;;16324:39;;-1:-1:-1;;;;;16324:30:0;;;:39;;;;;16355:7;;16324:39;;;;16355:7;16324:30;:39;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16324:39:0;16282:528;;;16412:12;;16457:20;;;-1:-1:-1;;;;;16457:20:0;;-1:-1:-1;;;;;16457:20:0;;;;;;;;;16412:12;;;;;16390;;16412;;16457:15;;:20;;;;;;;;;;;;;;16412:12;16457:20;;;5:2:-1;;;;30:1;27;20:12;5:2;16457:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16457:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;16457:20:0;16488:28;;;-1:-1:-1;;;;;16488:28:0;;-1:-1:-1;;;;;16488:28:0;;;;;;;;;;;;;;;16457:20;;-1:-1:-1;16488:14:0;;;;;;:28;;;;;16457:20;;16488:28;;;;;;;;-1:-1:-1;16488:14:0;:28;;;5:2:-1;;;;30:1;27;20:12;5:2;16488:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16488:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;16744:20:0;;;-1:-1:-1;;;;;16744:20:0;;-1:-1:-1;;;;;16744:20:0;;;;;;;;;16767:13;;16744:15;;;;;:20;;;;;16488:28;;16744:20;;;;;;;:15;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;16744:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16744:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;16744:20:0;:36;16736:64;;;;;-1:-1:-1;;;;;16736:64:0;;;;;;;;;;;;-1:-1:-1;;;;;16736:64:0;;;;;;;;;;;;;;66034:362;66182:4;66203:15;:2;-1:-1:-1;;;;;66203:13:0;;:15::i;:::-;66198:50;;-1:-1:-1;66236:4:0;66229:11;;66198:50;66270:78;;-1:-1:-1;;;;;66270:78:0;;66315:10;66270:78;;;;;;-1:-1:-1;;;;;66270:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;66254:13;;66270:36;;;;;;66315:10;;66327:4;;66333:7;;66342:5;;66270:78;;;;;;;;;;;66254:13;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;66270:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66270:78:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;66270:78:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;66270:78:0;-1:-1:-1;;;;;;66363:26:0;-1:-1:-1;;;;;66363:26:0;;-1:-1:-1;;66034:362:0;;;;;;:::o;52722:269::-;52924:58;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;52924:58:0;;;;;;;52914:69;;;;;;52722:269::o;50635:1930::-;50713:7;50776:9;:16;50796:2;50776:22;50772:74;;-1:-1:-1;50831:1:0;50815:19;;50772:74;51207:4;51192:20;;51186:27;51253:4;51238:20;;51232:27;51307:4;51292:20;;51286:27;50915:9;51278:36;52237:66;52224:79;;52220:129;;;52335:1;52320:17;;;;;;;52220:129;52365:1;:7;;52370:2;52365:7;;:18;;;;;52376:1;:7;;52381:2;52376:7;;52365:18;52361:68;;;52415:1;52400:17;;;;;;;52361:68;52533:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;52533:24:0;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;52533:24:0;;-1:-1:-1;;52533:24:0;;;50635:1930;-1:-1:-1;;;;;;;50635:1930:0:o;7284:476::-;7724:7;7712:20;7747:7;7284:476;:::o;9954:187::-;-1:-1:-1;;;;;10028:22:0;;10020:31;;;;;;10088:6;;10067:38;;-1:-1:-1;;;;;10067:38:0;;;;10088:6;;10067:38;;10088:6;;10067:38;10116:6;:17;;-1:-1:-1;;;;;;10116:17:0;-1:-1:-1;;;;;10116:17:0;;;;;;;;;;9954:187::o;31201:396::-;31279:12;;31275:317;;31440:16;:18;;;;;;;;31553:31;;31201:396::o;58845:627::-;59417:20;59456:8;;;58845:627::o;66845:1056::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;66845:1056:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66845:1056:0;;;-1:-1:-1;66845:1056:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;
Swarm Source
bzzr://31474d01281aa90a56dde5554eed5c93cdafcfbf9c58bfb98158409659343552
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.