- Contract name:
- OriumMarketplace
- Optimization enabled
- false
- Compiler version
- v0.8.9+commit.e5eed63a
- Verified at
- 2023-11-11T01:49:56.780158Z
contracts/OriumMarketplace.sol
// SPDX-License-Identifier: CC0-1.0 pragma solidity 0.8.9; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC7432, RoleAssignment } from "./interfaces/IERC7432.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; /** * @title Orium Marketplace - Marketplace for renting NFTs * @dev This contract is used to manage NFTs rentals, powered by ERC-7432 Non-Fungible Token Roles * @author Orium Network Team - [email protected] */ contract OriumMarketplace is Initializable, OwnableUpgradeable, PausableUpgradeable { /** ######### Constants ########### **/ /// @dev 100 ether is 100% uint256 public constant MAX_PERCENTAGE = 100 ether; /// @dev 2.5 ether is 2.5% uint256 public constant DEFAULT_FEE_PERCENTAGE = 2.5 ether; /** ######### Global Variables ########### **/ /// @dev rolesRegistry is a ERC-7432 contract address public defaultRolesRegistry; /// @dev tokenAddress => rolesRegistry mapping(address => address) public tokenRolesRegistry; /// @dev deadline is set in seconds uint256 public maxDeadline; /// @dev tokenAddress => feePercentageInWei mapping(address => FeeInfo) public feeInfo; /// @dev tokenAddress => royaltyInfo mapping(address => RoyaltyInfo) public royaltyInfo; /// @dev hashedOffer => bool mapping(bytes32 => bool) public isCreated; /// @dev lender => nonce => deadline mapping(address => mapping(uint256 => uint64)) public nonceDeadline; /// @dev hashedOffer => Rental mapping(bytes32 => Rental) public rentals; /** ######### Structs ########### **/ struct Rental { address borrower; uint64 expirationDate; } /// @dev Royalty info. Used to charge fees for the creator. struct RoyaltyInfo { address creator; uint256 royaltyPercentageInWei; address treasury; } /// @dev Marketplace fee info. struct FeeInfo { uint256 feePercentageInWei; bool isCustomFee; } /// @dev Rental offer info. struct RentalOffer { address lender; address borrower; address tokenAddress; uint256 tokenId; address feeTokenAddress; uint256 feeAmountPerSecond; uint256 nonce; uint64 deadline; bytes32[] roles; bytes[] rolesData; } /// @dev Direct rental info. struct DirectRental { address tokenAddress; uint256 tokenId; address lender; address borrower; uint64 duration; bytes32[] roles; bytes[] rolesData; } /** ######### Events ########### **/ /** * @param tokenAddress The NFT address. * @param feePercentageInWei The fee percentage in wei. * @param isCustomFee If the fee is custom or not. Used to allow collections with no fee. */ event MarketplaceFeeSet(address indexed tokenAddress, uint256 feePercentageInWei, bool isCustomFee); /** * @param tokenAddress The NFT address. * @param creator The address of the creator. * @param royaltyPercentageInWei The royalty percentage in wei. * @param treasury The address where the fees will be sent. If the treasury is address(0), the fees will be burned. */ event CreatorRoyaltySet( address indexed tokenAddress, address indexed creator, uint256 royaltyPercentageInWei, address treasury ); /** * @param nonce The nonce of the rental offer * @param tokenAddress The address of the contract of the NFT to rent * @param tokenId The tokenId of the NFT to rent * @param lender The address of the user lending the NFT * @param borrower The address of the user renting the NFT * @param feeTokenAddress The address of the ERC20 token for rental fees * @param feeAmountPerSecond The amount of fee per second * @param deadline The deadline until when the rental offer is valid * @param roles The array of roles to be assigned to the borrower * @param rolesData The array of data for each role */ event RentalOfferCreated( uint256 indexed nonce, address indexed tokenAddress, uint256 indexed tokenId, address lender, address borrower, address feeTokenAddress, uint256 feeAmountPerSecond, uint256 deadline, bytes32[] roles, bytes[] rolesData ); /** * @param nonce The nonce of the rental offer * @param tokenAddress The address of the contract of the NFT rented * @param tokenId The tokenId of the rented NFT * @param lender The address of the lender * @param borrower The address of the borrower * @param expirationDate The expiration date of the rental */ event RentalStarted( uint256 indexed nonce, address indexed tokenAddress, uint256 indexed tokenId, address lender, address borrower, uint64 expirationDate ); /** * @param nonce The nonce of the rental offer * @param lender The address of the user lending the NFT */ event RentalOfferCancelled(uint256 indexed nonce, address indexed lender); /** * @param nonce The nonce of the rental offer * @param tokenAddress The address of the contract of the NFT rented * @param tokenId The tokenId of the rented NFT * @param lender The address of the lender * @param borrower The address of the borrower */ event RentalEnded( uint256 indexed nonce, address indexed tokenAddress, uint256 indexed tokenId, address lender, address borrower ); /** * @param tokenAddress The NFT address. * @param rolesRegistry The address of the roles registry. */ event RolesRegistrySet(address indexed tokenAddress, address indexed rolesRegistry); /** * @param directRentalHash The hash of the direct rental * @param tokenAddress The address of the contract of the NFT rented * @param tokenId The tokenId of the rented NFT * @param lender The address of the lender * @param borrower The address of the borrower * @param duration The duration of the rental * @param roles The array of roles to be assigned to the borrower * @param rolesData The array of data for each role */ event DirectRentalStarted( bytes32 indexed directRentalHash, address indexed tokenAddress, uint256 indexed tokenId, address lender, address borrower, uint256 duration, bytes32[] roles, bytes[] rolesData ); /** * @param directRentalHash The hash of the direct rental * @param lender The address of the user lending the NFT */ event DirectRentalEnded(bytes32 indexed directRentalHash, address indexed lender); /** ######### Modifiers ########### **/ /** * @notice Checks the ownership of the token. * @dev Throws if the caller is not the owner of the token. * @param _tokenAddress The NFT address. * @param _tokenId The id of the token. */ modifier onlyTokenOwner(address _tokenAddress, uint256 _tokenId) { require( msg.sender == IERC721(_tokenAddress).ownerOf(_tokenId), "OriumMarketplace: only token owner can call this function" ); _; } /** ######### Initializer ########### **/ /** * @notice Initializes the contract. * @dev The owner of the contract will be the owner of the protocol. * @param _owner The owner of the protocol. * @param _defaultRolesRegistry The address of the roles registry. * @param _maxDeadline The maximum deadline. */ function initialize(address _owner, address _defaultRolesRegistry, uint256 _maxDeadline) public initializer { __Pausable_init(); __Ownable_init(); defaultRolesRegistry = _defaultRolesRegistry; maxDeadline = _maxDeadline; transferOwnership(_owner); } /** ============================ Rental Functions ================================== **/ /** ######### Setters ########### **/ /** * @notice Creates a rental offer. * @dev To optimize for gas, only the offer hash is stored on-chain * @param _offer The rental offer struct. */ function createRentalOffer( RentalOffer calldata _offer ) external onlyTokenOwner(_offer.tokenAddress, _offer.tokenId) { _validateCreateRentalOffer(_offer); bytes32 _offerHash = hashRentalOffer(_offer); nonceDeadline[msg.sender][_offer.nonce] = _offer.deadline; isCreated[_offerHash] = true; emit RentalOfferCreated( _offer.nonce, _offer.tokenAddress, _offer.tokenId, _offer.lender, _offer.borrower, _offer.feeTokenAddress, _offer.feeAmountPerSecond, _offer.deadline, _offer.roles, _offer.rolesData ); } /** * @dev Validates the create rental offer. * @param _offer The rental offer struct. */ function _validateCreateRentalOffer(RentalOffer calldata _offer) internal view { require(_offer.nonce != 0, "OriumMarketplace: Nonce cannot be 0"); require(msg.sender == _offer.lender, "OriumMarketplace: Sender and Lender mismatch"); require(_offer.roles.length > 0, "OriumMarketplace: roles should not be empty"); require( _offer.roles.length == _offer.rolesData.length, "OriumMarketplace: roles and rolesData should have the same length" ); require( _offer.deadline <= block.timestamp + maxDeadline && _offer.deadline > block.timestamp, "OriumMarketplace: Invalid deadline" ); require(nonceDeadline[_offer.lender][_offer.nonce] == 0, "OriumMarketplace: nonce already used"); } function cancelRentalOffer(uint256 nonce) external { require(nonceDeadline[msg.sender][nonce] > block.timestamp, "OriumMarketplace: Nonce expired or not used yet"); nonceDeadline[msg.sender][nonce] = uint64(block.timestamp); emit RentalOfferCancelled(nonce, msg.sender); } /** * @notice Accepts a rental offer. * @dev The borrower can be address(0) to allow anyone to rent the NFT. * @param _offer The rental offer struct. It should be the same as the one used to create the offer. * @param _duration The duration of the rental. */ function acceptRentalOffer(RentalOffer calldata _offer, uint64 _duration) external { uint64 _expirationDate = uint64(block.timestamp + _duration); _validateAcceptRentalOffer(_offer, _expirationDate); _transferFees(_offer.tokenAddress, _offer.feeTokenAddress, _offer.feeAmountPerSecond, _duration, _offer.lender); _batchGrantRole( _offer.roles, _offer.rolesData, _offer.tokenAddress, _offer.tokenId, _offer.lender, msg.sender, _expirationDate, false ); rentals[hashRentalOffer(_offer)] = Rental({ borrower: msg.sender, expirationDate: _expirationDate }); emit RentalStarted( _offer.nonce, _offer.tokenAddress, _offer.tokenId, _offer.lender, msg.sender, _expirationDate ); } /** * @dev Validates the accept rental offer. * @param _offer The rental offer struct. It should be the same as the one used to create the offer. * @param _expirationDate The period of time the NFT will be rented. */ function _validateAcceptRentalOffer(RentalOffer calldata _offer, uint64 _expirationDate) internal view { bytes32 _offerHash = hashRentalOffer(_offer); require(rentals[_offerHash].expirationDate <= block.timestamp, "OriumMarketplace: Rental already started"); require(isCreated[_offerHash], "OriumMarketplace: Offer not created"); require( address(0) == _offer.borrower || msg.sender == _offer.borrower, "OriumMarketplace: Sender is not allowed to rent this NFT" ); require( nonceDeadline[_offer.lender][_offer.nonce] > _expirationDate, "OriumMarketplace: expiration date is greater than offer deadline" ); } /** * @dev Transfers the fees to the marketplace, the creator and the lender. * @param _feeTokenAddress The address of the ERC20 token for rental fees. * @param _feeAmountPerSecond The amount of fee per second. * @param _duration The duration of the rental. * @param _lenderAddress The address of the lender. */ function _transferFees( address _tokenAddress, address _feeTokenAddress, uint256 _feeAmountPerSecond, uint64 _duration, address _lenderAddress ) internal { uint256 _feeAmount = _feeAmountPerSecond * _duration; if (_feeAmount == 0) return; uint256 _marketplaceFeeAmount = _getAmountFromPercentage(_feeAmount, marketplaceFeeOf(_tokenAddress)); if (_marketplaceFeeAmount > 0) { require( IERC20(_feeTokenAddress).transferFrom(msg.sender, owner(), _marketplaceFeeAmount), "OriumMarketplace: Transfer failed" ); } uint256 _royaltyAmount = _getAmountFromPercentage( _feeAmount, royaltyInfo[_tokenAddress].royaltyPercentageInWei ); if (_royaltyAmount > 0) { require( IERC20(_feeTokenAddress).transferFrom(msg.sender, royaltyInfo[_tokenAddress].treasury, _royaltyAmount), "OriumMarketplace: Transfer failed" ); } uint256 _lenderAmount = _feeAmount - _royaltyAmount - _marketplaceFeeAmount; require( IERC20(_feeTokenAddress).transferFrom(msg.sender, _lenderAddress, _lenderAmount), "OriumMarketplace: Transfer failed" ); // TODO: Change to vesting contract address later } /** * @dev All values needs to be in wei. * @param _amount The amount to calculate the percentage from. * @param _percentage The percentage to calculate. */ function _getAmountFromPercentage(uint256 _amount, uint256 _percentage) internal pure returns (uint256) { return (_amount * _percentage) / MAX_PERCENTAGE; } /** * @dev Grants the roles to the borrower. * @param _roles The array of roles to be assigned to the borrower * @param _rolesData The array of data for each role * @param _tokenAddress The address of the contract of the NFT to rent * @param _tokenId The tokenId of the NFT to rent * @param _grantor The address of the user lending the NFT * @param _grantee The address of the user renting the NFT * @param _expirationDate The deadline until when the rental offer is valid */ function _batchGrantRole( bytes32[] memory _roles, bytes[] memory _rolesData, address _tokenAddress, uint256 _tokenId, address _grantor, address _grantee, uint64 _expirationDate, bool _revocable ) internal { address _rolesRegistry = rolesRegistryOf(_tokenAddress); for (uint256 i = 0; i < _roles.length; i++) { _grantUniqueRoleChecked( // Needed to avoid stack too deep error _roles[i], _tokenAddress, _tokenId, _grantor, _grantee, _expirationDate, _rolesData[i], _rolesRegistry, _revocable ); } } /** * @dev Grants the role to the borrower. * @param _role The role to be granted * @param _tokenAddress The address of the contract of the NFT to rent * @param _tokenId The tokenId of the NFT to rent * @param _grantor The address of the user lending the NFT * @param _grantee The address of the user renting the NFT * @param _expirationDate The deadline until when the rental offer is valid * @param _data The data for the role */ function _grantUniqueRoleChecked( bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantor, address _grantee, uint64 _expirationDate, bytes memory _data, address _rolesRegistry, bool _revocable ) internal { RoleAssignment memory _roleAssignment = RoleAssignment({ role: _role, tokenAddress: _tokenAddress, tokenId: _tokenId, grantor: _grantor, grantee: _grantee, expirationDate: _expirationDate, data: _data }); if (_revocable) { IERC7432(_rolesRegistry).grantRevocableRoleFrom(_roleAssignment); } else { IERC7432(_rolesRegistry).grantRoleFrom(_roleAssignment); } } /** * @notice Ends the rental. * @dev Can only be called by the borrower. * @dev Borrower needs to approve marketplace to revoke the roles. * @param _offer The rental offer struct. It should be the same as the one used to create the offer. */ function endRental(RentalOffer memory _offer) external { bytes32 _offerHash = hashRentalOffer(_offer); _validateEndRental(_offer, _offerHash); _batchRevokeRole( _offer.roles, _offer.tokenAddress, _offer.tokenId, _offer.lender, rentals[_offerHash].borrower ); rentals[_offerHash].expirationDate = uint64(block.timestamp); emit RentalEnded( _offer.nonce, _offer.tokenAddress, _offer.tokenId, _offer.lender, rentals[_offerHash].borrower ); } /** * @dev Validates the end rental. * @param _offer The rental offer struct. It should be the same as the one used to create the offer. * @param _offerHash The hash of the rental offer struct. */ function _validateEndRental(RentalOffer memory _offer, bytes32 _offerHash) internal view { require(isCreated[_offerHash], "OriumMarketplace: Offer not created"); require(msg.sender == rentals[_offerHash].borrower, "OriumMarketplace: Only borrower can end a rental"); require(nonceDeadline[_offer.lender][_offer.nonce] > block.timestamp, "OriumMarketplace: Rental Offer expired"); require(rentals[_offerHash].expirationDate > block.timestamp, "OriumMarketplace: Rental ended"); } /** * @dev Revokes the roles from the borrower. * @param _roles The array of roles to be revoked from the borrower * @param _tokenAddress The address of the contract of the NFT to rent * @param _tokenId The tokenId of the NFT to rent * @param _grantor The address of the user lending the NFT * @param _grantee The address of the user renting the NFT */ function _batchRevokeRole( bytes32[] memory _roles, address _tokenAddress, uint256 _tokenId, address _grantor, address _grantee ) internal { address _rolesRegistry = rolesRegistryOf(_tokenAddress); for (uint256 i = 0; i < _roles.length; i++) { IERC7432(_rolesRegistry).revokeRoleFrom(_roles[i], _tokenAddress, _tokenId, _grantor, _grantee); } } /** * @notice Creates a direct rental. * @dev The lender needs to approve marketplace to grant the roles. * @param _directRental The direct rental struct. */ function createDirectRental( DirectRental memory _directRental ) external onlyTokenOwner(_directRental.tokenAddress, _directRental.tokenId) { _validateCreateDirectRental(_directRental); bytes32 _hashedDirectRental = hashDirectRental(_directRental); uint64 _expirationDate = uint64(block.timestamp + _directRental.duration); isCreated[_hashedDirectRental] = true; rentals[_hashedDirectRental] = Rental({ borrower: _directRental.borrower, expirationDate: _expirationDate }); _batchGrantRole( _directRental.roles, _directRental.rolesData, _directRental.tokenAddress, _directRental.tokenId, _directRental.lender, _directRental.borrower, _expirationDate, true ); emit DirectRentalStarted( _hashedDirectRental, _directRental.tokenAddress, _directRental.tokenId, _directRental.lender, _directRental.borrower, _directRental.duration, _directRental.roles, _directRental.rolesData ); } /** * @dev Validates the create direct rental. * @param _directRental The direct rental struct. */ function _validateCreateDirectRental(DirectRental memory _directRental) internal view { require(_directRental.duration <= maxDeadline, "OriumMarketplace: Duration is greater than max deadline"); require(msg.sender == _directRental.lender, "OriumMarketplace: Sender and Lender mismatch"); require(_directRental.roles.length > 0, "OriumMarketplace: roles should not be empty"); require( _directRental.roles.length == _directRental.rolesData.length, "OriumMarketplace: roles and rolesData should have the same length" ); } /** * @notice Cancels a direct rental. * @dev The lender needs to approve marketplace to revoke the roles. * @param _directRental The direct rental struct. */ function cancelDirectRental(DirectRental memory _directRental) external { bytes32 _hashedDirectRental = hashDirectRental(_directRental); _validateCancelDirectRental(_directRental, _hashedDirectRental); rentals[_hashedDirectRental].expirationDate = uint64(block.timestamp); _batchRevokeRole( _directRental.roles, _directRental.tokenAddress, _directRental.tokenId, _directRental.lender, _directRental.borrower ); emit DirectRentalEnded(_hashedDirectRental, _directRental.lender); } function _validateCancelDirectRental(DirectRental memory _directRental, bytes32 _hashedDirectRental) internal view { require(isCreated[_hashedDirectRental], "OriumMarketplace: Direct rental not created"); require( rentals[_hashedDirectRental].expirationDate > block.timestamp, "OriumMarketplace: Direct rental expired" ); require( msg.sender == _directRental.lender || msg.sender == _directRental.borrower, "OriumMarketplace: Sender and Lender/Borrower mismatch" ); } /** ######### Getters ########### **/ /** * @notice Gets the rental offer hash. * @param _offer The rental offer struct to be hashed. */ function hashRentalOffer(RentalOffer memory _offer) public pure returns (bytes32) { return keccak256( abi.encode( _offer.lender, _offer.borrower, _offer.tokenAddress, _offer.tokenId, _offer.feeTokenAddress, _offer.feeAmountPerSecond, _offer.nonce, _offer.deadline, _offer.roles, _offer.rolesData ) ); } /** * @notice Gets the direct rental hash. * @param _directRental The direct rental struct to be hashed. */ function hashDirectRental(DirectRental memory _directRental) public pure returns (bytes32) { return keccak256( abi.encode( _directRental.tokenAddress, _directRental.tokenId, _directRental.lender, _directRental.borrower, _directRental.duration, _directRental.roles, _directRental.rolesData ) ); } /** ============================ Core Functions ================================== **/ /** ######### Setters ########### **/ /** * @notice Sets the roles registry. * @dev Only owner can set the roles registry. */ function pause() external onlyOwner { _pause(); } /** * @notice Unpauses the contract. * @dev Only owner can unpause the contract. */ function unpause() external onlyOwner { _unpause(); } /** * @notice Sets the marketplace fee for a collection. * @dev If no fee is set, the default fee will be used. * @param _tokenAddress The NFT address. * @param _feePercentageInWei The fee percentage in wei. * @param _isCustomFee If the fee is custom or not. */ function setMarketplaceFeeForCollection( address _tokenAddress, uint256 _feePercentageInWei, bool _isCustomFee ) external onlyOwner { uint256 _royaltyPercentage = royaltyInfo[_tokenAddress].royaltyPercentageInWei; require( _royaltyPercentage + _feePercentageInWei < MAX_PERCENTAGE, "OriumMarketplace: Royalty percentage + marketplace fee cannot be greater than 100%" ); feeInfo[_tokenAddress] = FeeInfo({ feePercentageInWei: _feePercentageInWei, isCustomFee: _isCustomFee }); emit MarketplaceFeeSet(_tokenAddress, _feePercentageInWei, _isCustomFee); } /** * @notice Sets the royalty info. * @dev Only owner can associate a collection with a creator. * @param _tokenAddress The NFT address. * @param _creator The address of the creator. */ function setCreator(address _tokenAddress, address _creator) external onlyOwner { _setRoyalty(_creator, _tokenAddress, 0, address(0)); } /** * @notice Sets the royalty info. * @param _tokenAddress The NFT address. * @param _royaltyPercentageInWei The royalty percentage in wei. * @param _treasury The address where the fees will be sent. If the treasury is address(0), the fees will be burned. */ function setRoyaltyInfo(address _tokenAddress, uint256 _royaltyPercentageInWei, address _treasury) external { require( msg.sender == royaltyInfo[_tokenAddress].creator, "OriumMarketplace: Only creator can set royalty info" ); _setRoyalty(msg.sender, _tokenAddress, _royaltyPercentageInWei, _treasury); } /** * @notice Sets the royalty info. * @dev Only owner can associate a collection with a creator. * @param _creator The address of the creator. * @param _tokenAddress The NFT address. * @param _royaltyPercentageInWei The royalty percentage in wei. * @param _treasury The address where the fees will be sent. If the treasury is address(0), the fees will be burned. */ function _setRoyalty( address _creator, address _tokenAddress, uint256 _royaltyPercentageInWei, address _treasury ) internal { require( _royaltyPercentageInWei + marketplaceFeeOf(_tokenAddress) < MAX_PERCENTAGE, "OriumMarketplace: Royalty percentage + marketplace fee cannot be greater than 100%" ); royaltyInfo[_tokenAddress] = RoyaltyInfo({ creator: _creator, royaltyPercentageInWei: _royaltyPercentageInWei, treasury: _treasury }); emit CreatorRoyaltySet(_tokenAddress, _creator, _royaltyPercentageInWei, _treasury); } /** * @notice Sets the maximum deadline. * @dev Only owner can set the maximum deadline. * @param _maxDeadline The maximum deadline. */ function setMaxDeadline(uint256 _maxDeadline) external onlyOwner { require(_maxDeadline > 0, "OriumMarketplace: Max deadline should be greater than 0"); maxDeadline = _maxDeadline; } /** * @notice Sets the roles registry for a collection. * @dev Only owner can set the roles registry for a collection. * @param _tokenAddress The NFT address. * @param _rolesRegistry The roles registry address. */ function setRolesRegistry(address _tokenAddress, address _rolesRegistry) external onlyOwner { tokenRolesRegistry[_tokenAddress] = _rolesRegistry; emit RolesRegistrySet(_tokenAddress, _rolesRegistry); } /** * @notice Sets the default roles registry. * @dev Only owner can set the default roles registry. * @param _rolesRegistry The roles registry address. */ function setDefaultRolesRegistry(address _rolesRegistry) external onlyOwner { defaultRolesRegistry = _rolesRegistry; } /** ######### Getters ########### **/ /** * @notice Gets the marketplace fee for a collection. * @dev If no custom fee is set, the default fee will be used. * @param _tokenAddress The NFT address. */ function marketplaceFeeOf(address _tokenAddress) public view returns (uint256) { return feeInfo[_tokenAddress].isCustomFee ? feeInfo[_tokenAddress].feePercentageInWei : DEFAULT_FEE_PERCENTAGE; } /** * @notice Gets the roles registry for a collection. * @dev If no custom roles registry is set, the default roles registry will be used. * @param _tokenAddress The NFT address. */ function rolesRegistryOf(address _tokenAddress) public view returns (address) { return tokenRolesRegistry[_tokenAddress] == address(0) ? defaultRolesRegistry : tokenRolesRegistry[_tokenAddress]; } }
@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
@openzeppelin/contracts/token/ERC721/IERC721.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
contracts/interfaces/IERC7432.sol
// SPDX-License-Identifier: CC0-1.0 pragma solidity 0.8.9; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; struct RoleData { uint64 expirationDate; bool revocable; bytes data; } struct RoleAssignment { bytes32 role; address tokenAddress; uint256 tokenId; address grantor; address grantee; uint64 expirationDate; bytes data; } /// @title ERC-7432 Non-Fungible Token Roles /// @dev See https://eips.ethereum.org/EIPS/eip-7432 /// Note: the ERC-165 identifier for this interface is 0x04984ac8. interface IERC7432 is IERC165 { /** Events **/ /// @notice Emitted when a role is granted. /// @param _role The role identifier. /// @param _tokenAddress The token address. /// @param _tokenId The token identifier. /// @param _grantor The user assigning the role. /// @param _grantee The user receiving the role. /// @param _expirationDate The expiration date of the role. /// @param _revocable Whether the role is revocable or not. /// @param _data Any additional data about the role. event RoleGranted( bytes32 indexed _role, address indexed _tokenAddress, uint256 indexed _tokenId, address _grantor, address _grantee, uint64 _expirationDate, bool _revocable, bytes _data ); /// @notice Emitted when a role is revoked. /// @param _role The role identifier. /// @param _tokenAddress The token address. /// @param _tokenId The token identifier. /// @param _revoker The user revoking the role. /// @param _grantee The user that receives the role revocation. event RoleRevoked( bytes32 indexed _role, address indexed _tokenAddress, uint256 indexed _tokenId, address _revoker, address _grantee ); /// @notice Emitted when a user is approved to manage any role on behalf of another user. /// @param _tokenAddress The token address. /// @param _operator The user approved to grant and revoke roles. /// @param _isApproved The approval status. event RoleApprovalForAll(address indexed _tokenAddress, address indexed _operator, bool _isApproved); /** External Functions **/ /// @notice Grants a role on behalf of a user. /// @param _roleAssignment The role assignment data. function grantRoleFrom(RoleAssignment calldata _roleAssignment) external; /// @notice Grants a role on behalf of a user. /// @param _roleAssignment The role assignment data. function grantRevocableRoleFrom(RoleAssignment calldata _roleAssignment) external; /// @notice Revokes a role on behalf of a user. /// @param _role The role identifier. /// @param _tokenAddress The token address. /// @param _tokenId The token identifier. /// @param _revoker The user revoking the role. /// @param _grantee The user that receives the role revocation. function revokeRoleFrom( bytes32 _role, address _tokenAddress, uint256 _tokenId, address _revoker, address _grantee ) external; /// @notice Approves operator to grant and revoke any roles on behalf of another user. /// @param _tokenAddress The token address. /// @param _operator The user approved to grant and revoke roles. /// @param _approved The approval status. function setRoleApprovalForAll(address _tokenAddress, address _operator, bool _approved) external; /** View Functions **/ /// @notice Checks if a user has a role. /// @param _role The role identifier. /// @param _tokenAddress The token address. /// @param _tokenId The token identifier. /// @param _grantor The user that assigned the role. /// @param _grantee The user that received the role. function hasNonUniqueRole( bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantor, address _grantee ) external view returns (bool); /// @notice Checks if a user has a unique role. /// @param _role The role identifier. /// @param _tokenAddress The token address. /// @param _tokenId The token identifier. /// @param _grantor The user that assigned the role. /// @param _grantee The user that received the role. function hasRole( bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantor, address _grantee ) external view returns (bool); /// @notice Returns the custom data of a role assignment. /// @param _role The role identifier. /// @param _tokenAddress The token address. /// @param _tokenId The token identifier. /// @param _grantor The user that assigned the role. /// @param _grantee The user that received the role. function roleData( bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantor, address _grantee ) external view returns (RoleData memory data_); /// @notice Returns the expiration date of a role assignment. /// @param _role The role identifier. /// @param _tokenAddress The token address. /// @param _tokenId The token identifier. /// @param _grantor The user that assigned the role. /// @param _grantee The user that received the role. function roleExpirationDate( bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantor, address _grantee ) external view returns (uint64 expirationDate_); /// @notice Checks if the grantor approved the operator for all NFTs. /// @param _tokenAddress The token address. /// @param _grantor The user that approved the operator. /// @param _operator The user that can grant and revoke roles. function isRoleApprovedForAll( address _tokenAddress, address _grantor, address _operator ) external view returns (bool); /// @notice Returns the last grantee of a role. /// @param _role The role. /// @param _tokenAddress The token address. /// @param _tokenId The token ID. /// @param _grantor The user that granted the role. function lastGrantee( bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantor ) external view returns (address); }
Contract ABI
[{"type":"event","name":"CreatorRoyaltySet","inputs":[{"type":"address","name":"tokenAddress","internalType":"address","indexed":true},{"type":"address","name":"creator","internalType":"address","indexed":true},{"type":"uint256","name":"royaltyPercentageInWei","internalType":"uint256","indexed":false},{"type":"address","name":"treasury","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"DirectRentalEnded","inputs":[{"type":"bytes32","name":"directRentalHash","internalType":"bytes32","indexed":true},{"type":"address","name":"lender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"DirectRentalStarted","inputs":[{"type":"bytes32","name":"directRentalHash","internalType":"bytes32","indexed":true},{"type":"address","name":"tokenAddress","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"lender","internalType":"address","indexed":false},{"type":"address","name":"borrower","internalType":"address","indexed":false},{"type":"uint256","name":"duration","internalType":"uint256","indexed":false},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]","indexed":false},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"MarketplaceFeeSet","inputs":[{"type":"address","name":"tokenAddress","internalType":"address","indexed":true},{"type":"uint256","name":"feePercentageInWei","internalType":"uint256","indexed":false},{"type":"bool","name":"isCustomFee","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"RentalEnded","inputs":[{"type":"uint256","name":"nonce","internalType":"uint256","indexed":true},{"type":"address","name":"tokenAddress","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"lender","internalType":"address","indexed":false},{"type":"address","name":"borrower","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"RentalOfferCancelled","inputs":[{"type":"uint256","name":"nonce","internalType":"uint256","indexed":true},{"type":"address","name":"lender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RentalOfferCreated","inputs":[{"type":"uint256","name":"nonce","internalType":"uint256","indexed":true},{"type":"address","name":"tokenAddress","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"lender","internalType":"address","indexed":false},{"type":"address","name":"borrower","internalType":"address","indexed":false},{"type":"address","name":"feeTokenAddress","internalType":"address","indexed":false},{"type":"uint256","name":"feeAmountPerSecond","internalType":"uint256","indexed":false},{"type":"uint256","name":"deadline","internalType":"uint256","indexed":false},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]","indexed":false},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]","indexed":false}],"anonymous":false},{"type":"event","name":"RentalStarted","inputs":[{"type":"uint256","name":"nonce","internalType":"uint256","indexed":true},{"type":"address","name":"tokenAddress","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"lender","internalType":"address","indexed":false},{"type":"address","name":"borrower","internalType":"address","indexed":false},{"type":"uint64","name":"expirationDate","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"RolesRegistrySet","inputs":[{"type":"address","name":"tokenAddress","internalType":"address","indexed":true},{"type":"address","name":"rolesRegistry","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DEFAULT_FEE_PERCENTAGE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_PERCENTAGE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptRentalOffer","inputs":[{"type":"tuple","name":"_offer","internalType":"struct OriumMarketplace.RentalOffer","components":[{"type":"address","name":"lender","internalType":"address"},{"type":"address","name":"borrower","internalType":"address"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"feeTokenAddress","internalType":"address"},{"type":"uint256","name":"feeAmountPerSecond","internalType":"uint256"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint64","name":"deadline","internalType":"uint64"},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]"},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]"}]},{"type":"uint64","name":"_duration","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelDirectRental","inputs":[{"type":"tuple","name":"_directRental","internalType":"struct OriumMarketplace.DirectRental","components":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"lender","internalType":"address"},{"type":"address","name":"borrower","internalType":"address"},{"type":"uint64","name":"duration","internalType":"uint64"},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]"},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelRentalOffer","inputs":[{"type":"uint256","name":"nonce","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createDirectRental","inputs":[{"type":"tuple","name":"_directRental","internalType":"struct OriumMarketplace.DirectRental","components":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"lender","internalType":"address"},{"type":"address","name":"borrower","internalType":"address"},{"type":"uint64","name":"duration","internalType":"uint64"},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]"},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createRentalOffer","inputs":[{"type":"tuple","name":"_offer","internalType":"struct OriumMarketplace.RentalOffer","components":[{"type":"address","name":"lender","internalType":"address"},{"type":"address","name":"borrower","internalType":"address"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"feeTokenAddress","internalType":"address"},{"type":"uint256","name":"feeAmountPerSecond","internalType":"uint256"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint64","name":"deadline","internalType":"uint64"},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]"},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"defaultRolesRegistry","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"endRental","inputs":[{"type":"tuple","name":"_offer","internalType":"struct OriumMarketplace.RentalOffer","components":[{"type":"address","name":"lender","internalType":"address"},{"type":"address","name":"borrower","internalType":"address"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"feeTokenAddress","internalType":"address"},{"type":"uint256","name":"feeAmountPerSecond","internalType":"uint256"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint64","name":"deadline","internalType":"uint64"},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]"},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"feePercentageInWei","internalType":"uint256"},{"type":"bool","name":"isCustomFee","internalType":"bool"}],"name":"feeInfo","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"hashDirectRental","inputs":[{"type":"tuple","name":"_directRental","internalType":"struct OriumMarketplace.DirectRental","components":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"lender","internalType":"address"},{"type":"address","name":"borrower","internalType":"address"},{"type":"uint64","name":"duration","internalType":"uint64"},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]"},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]"}]}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"hashRentalOffer","inputs":[{"type":"tuple","name":"_offer","internalType":"struct OriumMarketplace.RentalOffer","components":[{"type":"address","name":"lender","internalType":"address"},{"type":"address","name":"borrower","internalType":"address"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"feeTokenAddress","internalType":"address"},{"type":"uint256","name":"feeAmountPerSecond","internalType":"uint256"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint64","name":"deadline","internalType":"uint64"},{"type":"bytes32[]","name":"roles","internalType":"bytes32[]"},{"type":"bytes[]","name":"rolesData","internalType":"bytes[]"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_defaultRolesRegistry","internalType":"address"},{"type":"uint256","name":"_maxDeadline","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isCreated","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"marketplaceFeeOf","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxDeadline","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"nonceDeadline","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"borrower","internalType":"address"},{"type":"uint64","name":"expirationDate","internalType":"uint64"}],"name":"rentals","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"rolesRegistryOf","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"creator","internalType":"address"},{"type":"uint256","name":"royaltyPercentageInWei","internalType":"uint256"},{"type":"address","name":"treasury","internalType":"address"}],"name":"royaltyInfo","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCreator","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"address","name":"_creator","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDefaultRolesRegistry","inputs":[{"type":"address","name":"_rolesRegistry","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMarketplaceFeeForCollection","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_feePercentageInWei","internalType":"uint256"},{"type":"bool","name":"_isCustomFee","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxDeadline","inputs":[{"type":"uint256","name":"_maxDeadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRolesRegistry","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"address","name":"_rolesRegistry","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRoyaltyInfo","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_royaltyPercentageInWei","internalType":"uint256"},{"type":"address","name":"_treasury","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenRolesRegistry","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]}]
Contract Creation Code
0x608060405234801561001057600080fd5b50615b5780620000216000396000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c80637df8768e1161011a578063bfcfa66b116100ad578063e9ff836a1161007c578063e9ff836a1461059e578063f2fde38b146105ba578063f41440d9146105d6578063f9603a43146105f2578063fefbb15614610622576101fb565b8063bfcfa66b14610515578063cc3c3dea14610546578063de4e420114610562578063e724604214610580576101fb565b8063993c0f06116100e9578063993c0f061461047d578063a3e8fbce146104ad578063b5639182146104dd578063bf432a09146104f9576101fb565b80637df8768e146103f45780638456cb591461042557806386daff671461042f5780638da5cb5b1461045f576101fb565b806348b90a94116101925780636b7b11ab116101615780636b7b11ab146103945780636e09f420146103b25780636f6aae65146103ce578063715018a6146103ea576101fb565b806348b90a941461030a5780634c255c9714610326578063557d93bb146103445780635c975abb14610376576101fb565b806317450e18116101ce57806317450e18146102845780631794bb3c146102b45780632f553d31146102d05780633f4ba83a14610300576101fb565b80630152dc3b1461020057806303942b261461021c5780630d4995091461023857806311381bcd14610254575b600080fd5b61021a6004803603810190610215919061390e565b61063e565b005b61023660048036038101906102319190613957565b610782565b005b610252600480360381019061024d91906139aa565b610863565b005b61026e6004803603810190610269919061390e565b6108b8565b60405161027b91906139e6565b60405180910390f35b61029e60048036038101906102999190613a01565b610924565b6040516102ab9190613a3d565b60405180910390f35b6102ce60048036038101906102c99190613a58565b6109d3565b005b6102ea60048036038101906102e59190613aab565b610b6d565b6040516102f79190613af3565b60405180910390f35b610308610b8d565b005b610324600480360381019061031f9190613b33565b610b9f565b005b61032e610e6f565b60405161033b9190613a3d565b60405180910390f35b61035e60048036038101906103599190613a01565b610e7c565b60405161036d93929190613b8b565b60405180910390f35b61037e610ee6565b60405161038b9190613af3565b60405180910390f35b61039c610efd565b6040516103a99190613bc2565b60405180910390f35b6103cc60048036038101906103c791906139aa565b610f23565b005b6103e860048036038101906103e39190613cc9565b611091565b005b6103f261135a565b005b61040e60048036038101906104099190613aab565b61136e565b60405161041c929190613d21565b60405180910390f35b61042d6113c6565b005b61044960048036038101906104449190613a01565b6113d8565b6040516104569190613bc2565b60405180910390f35b61046761140b565b6040516104749190613bc2565b60405180910390f35b61049760048036038101906104929190613a01565b611435565b6040516104a49190613bc2565b60405180910390f35b6104c760048036038101906104c29190613d4a565b611559565b6040516104d49190613d8a565b60405180910390f35b6104f760048036038101906104f29190613cc9565b61158f565b005b610513600480360381019061050e9190613da5565b611650565b005b61052f600480360381019061052a9190613a01565b611734565b60405161053d929190613de5565b60405180910390f35b610560600480360381019061055b9190613a01565b611765565b005b61056a6117b1565b6040516105779190613a3d565b60405180910390f35b6105886117b7565b6040516105959190613a3d565b60405180910390f35b6105b860048036038101906105b39190613e0e565b6117c3565b005b6105d460048036038101906105cf9190613a01565b611a29565b005b6105f060048036038101906105eb9190613da5565b611aad565b005b61060c60048036038101906106079190613cc9565b611ac6565b60405161061991906139e6565b60405180910390f35b61063c60048036038101906106379190613e96565b611b1e565b005b6000610649826108b8565b90506106558282611c9c565b6106a9826101000151836040015184606001518560000151609e600087815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ed2565b42609e600083815260200190815260200160002060000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508160600151826040015173ffffffffffffffffffffffffffffffffffffffff168360c001517f64ab891e75e69c9ee4f25bb1f5ba3b22e6034af1ab9e6b7c3563b52baa9579f78560000151609e600087815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16604051610776929190613ee9565b60405180910390a45050565b609b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610852576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084990613f95565b60405180910390fd5b61085e33848484611f94565b505050565b61086b612180565b600081116108ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a590614027565b60405180910390fd5b8060998190555050565b6000816000015182602001518360400151846060015185608001518660a001518760c001518860e001518961010001518a61012001516040516020016109079a9998979695949392919061424f565b604051602081830303815290604052805190602001209050919050565b6000609a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160009054906101000a900460ff16610988576722b1c8c1227a00006109cc565b609a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001545b9050919050565b60008060019054906101000a900460ff16159050808015610a045750600160008054906101000a900460ff1660ff16105b80610a315750610a13306121fe565b158015610a305750600160008054906101000a900460ff1660ff16145b5b610a70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a679061436b565b60405180910390fd5b60016000806101000a81548160ff021916908360ff1602179055508015610aad576001600060016101000a81548160ff0219169083151502179055505b610ab5612221565b610abd61227a565b82609760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081609981905550610b0e84611a29565b8015610b675760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986001604051610b5e91906143dd565b60405180910390a15b50505050565b609c6020528060005260406000206000915054906101000a900460ff1681565b610b95612180565b610b9d6122d3565b565b806040016020810190610bb29190613a01565b81606001358173ffffffffffffffffffffffffffffffffffffffff16636352211e826040518263ffffffff1660e01b8152600401610bf09190613a3d565b60206040518083038186803b158015610c0857600080fd5b505afa158015610c1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c40919061440d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610cad576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca4906144ac565b60405180910390fd5b610cb683612336565b6000610cca84610cc5906144cc565b6108b8565b90508360e0016020810190610cdf91906144df565b609d60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008660c00135815260200190815260200160002060006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506001609c600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508360600135846040016020810190610d9d9190613a01565b73ffffffffffffffffffffffffffffffffffffffff168560c001357f645b3ecd64197738b74753003084af1cf404bf3569e2f7f682b8981cdff1f2b5876000016020810190610dec9190613a01565b886020016020810190610dff9190613a01565b896080016020810190610e129190613a01565b8a60a001358b60e0016020810190610e2a91906144df565b8c806101000190610e3b919061451b565b8e806101200190610e4c919061457e565b604051610e61999897969594939291906147b5565b60405180910390a450505050565b68056bc75e2d6310000081565b609b6020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000606560009054906101000a900460ff16905090565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b42609d60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff1611610fd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fca906148a8565b60405180910390fd5b42609d60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002060006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff16817fceb1a62b6c81ce110df60295368b21991cfac75365f3cb21b27995d37d3ee03360405160405180910390a350565b806000015181602001518173ffffffffffffffffffffffffffffffffffffffff16636352211e826040518263ffffffff1660e01b81526004016110d49190613a3d565b60206040518083038186803b1580156110ec57600080fd5b505afa158015611100573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611124919061440d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611191576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611188906144ac565b60405180910390fd5b61119a83612616565b60006111a584611ac6565b90506000846080015167ffffffffffffffff16426111c391906148f7565b90506001609c600084815260200190815260200160002060006101000a81548160ff0219169083151502179055506040518060400160405280866060015173ffffffffffffffffffffffffffffffffffffffff1681526020018267ffffffffffffffff16815250609e600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055509050506112df8560a001518660c001518760000151886020015189604001518a60600151876001612772565b8460200151856000015173ffffffffffffffffffffffffffffffffffffffff16837f83ec018773fb2d9f2be26dcc9ad0bf29bd25f47a150e354ac942a77e71729978886040015189606001518a608001518b60a001518c60c0015160405161134b95949392919061494d565b60405180910390a45050505050565b611362612180565b61136c60006127ef565b565b609e6020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900467ffffffffffffffff16905082565b6113ce612180565b6113d66128b5565b565b60986020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008073ffffffffffffffffffffffffffffffffffffffff16609860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461152e57609860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611552565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b9050919050565b609d6020528160005260406000206020528060005260406000206000915091509054906101000a900467ffffffffffffffff1681565b600061159a82611ac6565b90506115a68282612918565b42609e600083815260200190815260200160002060000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506116048260a001518360000151846020015185604001518660600151611ed2565b816040015173ffffffffffffffffffffffffffffffffffffffff16817fc955c36f0072545b860e915eb3f3ca5e1a61046cde3c9a01d237ae2cdd6df44d60405160405180910390a35050565b611658612180565b80609860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fe4439c77c292ccd794f87871827c1bac9053f5900ac32b62c734678ddd1d01c760405160405180910390a35050565b609a6020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16905082565b61176d612180565b80609760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60995481565b6722b1c8c1227a000081565b60008167ffffffffffffffff16426117db91906148f7565b90506117e78382612a9e565b61182e8360400160208101906117fd9190613a01565b8460800160208101906118109190613a01565b8560a00135858760000160208101906118299190613a01565b612d29565b6118d283806101000190611842919061451b565b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505084806101200190611893919061457e565b9061189e91906149ae565b8560400160208101906118b19190613a01565b86606001358760000160208101906118c99190613a01565b33876000612772565b60405180604001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018267ffffffffffffffff16815250609e600061191d86611918906144cc565b6108b8565b815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555090505082606001358360400160208101906119bc9190613a01565b73ffffffffffffffffffffffffffffffffffffffff168460c001357f6ac7cb5ec310cf58d38b9b4b1b9dc4314b1540a5eb85c468fe90a80d27673871866000016020810190611a0b9190613a01565b3386604051611a1c939291906149c3565b60405180910390a4505050565b611a31612180565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611aa1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a9890614a6c565b60405180910390fd5b611aaa816127ef565b50565b611ab5612180565b611ac28183600080611f94565b5050565b6000816000015182602001518360400151846060015185608001518660a001518760c00151604051602001611b019796959493929190614a8c565b604051602081830303815290604052805190602001209050919050565b611b26612180565b6000609b60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010154905068056bc75e2d631000008382611b8391906148f7565b10611bc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bba90614ba1565b60405180910390fd5b6040518060400160405280848152602001831515815250609a60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff0219169083151502179055509050508373ffffffffffffffffffffffffffffffffffffffff167fc60e6f659e43dc4ad63d5a27cea2b5bd7b775ea5a9f1e8f4ba2dd4566809b5098484604051611c8e929190613de5565b60405180910390a250505050565b609c600082815260200190815260200160002060009054906101000a900460ff16611cfc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cf390614c33565b60405180910390fd5b609e600082815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611da0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d9790614cc5565b60405180910390fd5b42609d6000846000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008460c00151815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff1611611e58576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e4f90614d57565b60405180910390fd5b42609e600083815260200190815260200160002060000160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1611611ece576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ec590614dc3565b60405180910390fd5b5050565b6000611edd85611435565b905060005b8651811015611f8b578173ffffffffffffffffffffffffffffffffffffffff1663a9c39982888381518110611f1a57611f19614de3565b5b6020026020010151888888886040518663ffffffff1660e01b8152600401611f46959493929190614e12565b600060405180830381600087803b158015611f6057600080fd5b505af1158015611f74573d6000803e3d6000fd5b505050508080611f8390614e65565b915050611ee2565b50505050505050565b68056bc75e2d63100000611fa784610924565b83611fb291906148f7565b10611ff2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fe990614ba1565b60405180910390fd5b60405180606001604052808573ffffffffffffffffffffffffffffffffffffffff1681526020018381526020018273ffffffffffffffffffffffffffffffffffffffff16815250609b60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f48ad8485693b9973ead8f2419c47217555f7b8197a637de45e68b507779aee778484604051612172929190614eae565b60405180910390a350505050565b6121886130c6565b73ffffffffffffffffffffffffffffffffffffffff166121a661140b565b73ffffffffffffffffffffffffffffffffffffffff16146121fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121f390614f23565b60405180910390fd5b565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600060019054906101000a900460ff16612270576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161226790614fb5565b60405180910390fd5b6122786130ce565b565b600060019054906101000a900460ff166122c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122c090614fb5565b60405180910390fd5b6122d161313a565b565b6122db61319b565b6000606560006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61231f6130c6565b60405161232c9190613bc2565b60405180910390a1565b60008160c00135141561237e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161237590615047565b60405180910390fd5b8060000160208101906123919190613a01565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146123fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123f5906150d9565b60405180910390fd5b600081806101000190612411919061451b565b905011612453576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161244a9061516b565b60405180910390fd5b80806101200190612464919061457e565b905081806101000190612477919061451b565b9050146124b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124b090615223565b60405180910390fd5b609954426124c791906148f7565b8160e00160208101906124da91906144df565b67ffffffffffffffff161115801561250d5750428160e001602081019061250191906144df565b67ffffffffffffffff16115b61254c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612543906152b5565b60405180910390fd5b6000609d60008360000160208101906125659190613a01565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008360c00135815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff1614612613576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161260a90615347565b60405180910390fd5b50565b609954816080015167ffffffffffffffff161115612669576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612660906153d9565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146126db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126d2906150d9565b60405180910390fd5b60008160a001515111612723576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161271a9061516b565b60405180910390fd5b8060c00151518160a00151511461276f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161276690615223565b60405180910390fd5b50565b600061277d87611435565b905060005b89518110156127e3576127d08a82815181106127a1576127a0614de3565b5b602002602001015189898989898f88815181106127c1576127c0614de3565b5b6020026020010151898b6131e4565b80806127db90614e65565b915050612782565b50505050505050505050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6128bd613355565b6001606560006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586129016130c6565b60405161290e9190613bc2565b60405180910390a1565b609c600082815260200190815260200160002060009054906101000a900460ff16612978576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161296f9061546b565b60405180910390fd5b42609e600083815260200190815260200160002060000160149054906101000a900467ffffffffffffffff1667ffffffffffffffff16116129ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129e5906154fd565b60405180910390fd5b816040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480612a5b5750816060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b612a9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a919061558f565b60405180910390fd5b5050565b6000612ab283612aad906144cc565b6108b8565b905042609e600083815260200190815260200160002060000160149054906101000a900467ffffffffffffffff1667ffffffffffffffff161115612b2b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b2290615621565b60405180910390fd5b609c600082815260200190815260200160002060009054906101000a900460ff16612b8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b8290614c33565b60405180910390fd5b826020016020810190612b9e9190613a01565b73ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff161480612c155750826020016020810190612be69190613a01565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b612c54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c4b906156b3565b60405180910390fd5b8167ffffffffffffffff16609d6000856000016020810190612c769190613a01565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008560c00135815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff1611612d24576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d1b90615745565b60405180910390fd5b505050565b60008267ffffffffffffffff1684612d419190615765565b90506000811415612d5257506130bf565b6000612d6682612d6189610924565b61339f565b90506000811115612e47578573ffffffffffffffffffffffffffffffffffffffff166323b872dd33612d9661140b565b846040518463ffffffff1660e01b8152600401612db5939291906157bf565b602060405180830381600087803b158015612dcf57600080fd5b505af1158015612de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e07919061580b565b612e46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e3d906158aa565b60405180910390fd5b5b6000612e9583609b60008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015461339f565b90506000811115612fd1578673ffffffffffffffffffffffffffffffffffffffff166323b872dd33609b60008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518463ffffffff1660e01b8152600401612f3f939291906157bf565b602060405180830381600087803b158015612f5957600080fd5b505af1158015612f6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f91919061580b565b612fd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612fc7906158aa565b60405180910390fd5b5b6000828285612fe091906158ca565b612fea91906158ca565b90508773ffffffffffffffffffffffffffffffffffffffff166323b872dd3387846040518463ffffffff1660e01b8152600401613029939291906157bf565b602060405180830381600087803b15801561304357600080fd5b505af1158015613057573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061307b919061580b565b6130ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130b1906158aa565b60405180910390fd5b505050505b5050505050565b600033905090565b600060019054906101000a900460ff1661311d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161311490614fb5565b60405180910390fd5b6000606560006101000a81548160ff021916908315150217905550565b600060019054906101000a900460ff16613189576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161318090614fb5565b60405180910390fd5b6131996131946130c6565b6127ef565b565b6131a3610ee6565b6131e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016131d99061594a565b60405180910390fd5b565b60006040518060e001604052808b81526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018667ffffffffffffffff16815260200185815250905081156132dd578273ffffffffffffffffffffffffffffffffffffffff166344c722cf826040518263ffffffff1660e01b81526004016132a69190615a33565b600060405180830381600087803b1580156132c057600080fd5b505af11580156132d4573d6000803e3d6000fd5b50505050613349565b8273ffffffffffffffffffffffffffffffffffffffff16639760a9e1826040518263ffffffff1660e01b81526004016133169190615a33565b600060405180830381600087803b15801561333057600080fd5b505af1158015613344573d6000803e3d6000fd5b505050505b50505050505050505050565b61335d610ee6565b1561339d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161339490615aa1565b60405180910390fd5b565b600068056bc75e2d6310000082846133b79190615765565b6133c19190615af0565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61342b826133e2565b810181811067ffffffffffffffff8211171561344a576134496133f3565b5b80604052505050565b600061345d6133c9565b90506134698282613422565b919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061349e82613473565b9050919050565b6134ae81613493565b81146134b957600080fd5b50565b6000813590506134cb816134a5565b92915050565b6000819050919050565b6134e4816134d1565b81146134ef57600080fd5b50565b600081359050613501816134db565b92915050565b600067ffffffffffffffff82169050919050565b61352481613507565b811461352f57600080fd5b50565b6000813590506135418161351b565b92915050565b600080fd5b600067ffffffffffffffff821115613567576135666133f3565b5b602082029050602081019050919050565b600080fd5b6000819050919050565b6135908161357d565b811461359b57600080fd5b50565b6000813590506135ad81613587565b92915050565b60006135c66135c18461354c565b613453565b905080838252602082019050602084028301858111156135e9576135e8613578565b5b835b8181101561361257806135fe888261359e565b8452602084019350506020810190506135eb565b5050509392505050565b600082601f83011261363157613630613547565b5b81356136418482602086016135b3565b91505092915050565b600067ffffffffffffffff821115613665576136646133f3565b5b602082029050602081019050919050565b600080fd5b600067ffffffffffffffff821115613696576136956133f3565b5b61369f826133e2565b9050602081019050919050565b82818337600083830152505050565b60006136ce6136c98461367b565b613453565b9050828152602081018484840111156136ea576136e9613676565b5b6136f58482856136ac565b509392505050565b600082601f83011261371257613711613547565b5b81356137228482602086016136bb565b91505092915050565b600061373e6137398461364a565b613453565b9050808382526020820190506020840283018581111561376157613760613578565b5b835b818110156137a857803567ffffffffffffffff81111561378657613785613547565b5b80860161379389826136fd565b85526020850194505050602081019050613763565b5050509392505050565b600082601f8301126137c7576137c6613547565b5b81356137d784826020860161372b565b91505092915050565b600061014082840312156137f7576137f66133dd565b5b613802610140613453565b90506000613812848285016134bc565b6000830152506020613826848285016134bc565b602083015250604061383a848285016134bc565b604083015250606061384e848285016134f2565b6060830152506080613862848285016134bc565b60808301525060a0613876848285016134f2565b60a08301525060c061388a848285016134f2565b60c08301525060e061389e84828501613532565b60e08301525061010082013567ffffffffffffffff8111156138c3576138c261346e565b5b6138cf8482850161361c565b6101008301525061012082013567ffffffffffffffff8111156138f5576138f461346e565b5b613901848285016137b2565b6101208301525092915050565b600060208284031215613924576139236133d3565b5b600082013567ffffffffffffffff811115613942576139416133d8565b5b61394e848285016137e0565b91505092915050565b6000806000606084860312156139705761396f6133d3565b5b600061397e868287016134bc565b935050602061398f868287016134f2565b92505060406139a0868287016134bc565b9150509250925092565b6000602082840312156139c0576139bf6133d3565b5b60006139ce848285016134f2565b91505092915050565b6139e08161357d565b82525050565b60006020820190506139fb60008301846139d7565b92915050565b600060208284031215613a1757613a166133d3565b5b6000613a25848285016134bc565b91505092915050565b613a37816134d1565b82525050565b6000602082019050613a526000830184613a2e565b92915050565b600080600060608486031215613a7157613a706133d3565b5b6000613a7f868287016134bc565b9350506020613a90868287016134bc565b9250506040613aa1868287016134f2565b9150509250925092565b600060208284031215613ac157613ac06133d3565b5b6000613acf8482850161359e565b91505092915050565b60008115159050919050565b613aed81613ad8565b82525050565b6000602082019050613b086000830184613ae4565b92915050565b600080fd5b60006101408284031215613b2a57613b29613b0e565b5b81905092915050565b600060208284031215613b4957613b486133d3565b5b600082013567ffffffffffffffff811115613b6757613b666133d8565b5b613b7384828501613b13565b91505092915050565b613b8581613493565b82525050565b6000606082019050613ba06000830186613b7c565b613bad6020830185613a2e565b613bba6040830184613b7c565b949350505050565b6000602082019050613bd76000830184613b7c565b92915050565b600060e08284031215613bf357613bf26133dd565b5b613bfd60e0613453565b90506000613c0d848285016134bc565b6000830152506020613c21848285016134f2565b6020830152506040613c35848285016134bc565b6040830152506060613c49848285016134bc565b6060830152506080613c5d84828501613532565b60808301525060a082013567ffffffffffffffff811115613c8157613c8061346e565b5b613c8d8482850161361c565b60a08301525060c082013567ffffffffffffffff811115613cb157613cb061346e565b5b613cbd848285016137b2565b60c08301525092915050565b600060208284031215613cdf57613cde6133d3565b5b600082013567ffffffffffffffff811115613cfd57613cfc6133d8565b5b613d0984828501613bdd565b91505092915050565b613d1b81613507565b82525050565b6000604082019050613d366000830185613b7c565b613d436020830184613d12565b9392505050565b60008060408385031215613d6157613d606133d3565b5b6000613d6f858286016134bc565b9250506020613d80858286016134f2565b9150509250929050565b6000602082019050613d9f6000830184613d12565b92915050565b60008060408385031215613dbc57613dbb6133d3565b5b6000613dca858286016134bc565b9250506020613ddb858286016134bc565b9150509250929050565b6000604082019050613dfa6000830185613a2e565b613e076020830184613ae4565b9392505050565b60008060408385031215613e2557613e246133d3565b5b600083013567ffffffffffffffff811115613e4357613e426133d8565b5b613e4f85828601613b13565b9250506020613e6085828601613532565b9150509250929050565b613e7381613ad8565b8114613e7e57600080fd5b50565b600081359050613e9081613e6a565b92915050565b600080600060608486031215613eaf57613eae6133d3565b5b6000613ebd868287016134bc565b9350506020613ece868287016134f2565b9250506040613edf86828701613e81565b9150509250925092565b6000604082019050613efe6000830185613b7c565b613f0b6020830184613b7c565b9392505050565b600082825260208201905092915050565b7f4f7269756d4d61726b6574706c6163653a204f6e6c792063726561746f72206360008201527f616e2073657420726f79616c747920696e666f00000000000000000000000000602082015250565b6000613f7f603383613f12565b9150613f8a82613f23565b604082019050919050565b60006020820190508181036000830152613fae81613f72565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204d617820646561646c696e65207360008201527f686f756c642062652067726561746572207468616e2030000000000000000000602082015250565b6000614011603783613f12565b915061401c82613fb5565b604082019050919050565b6000602082019050818103600083015261404081614004565b9050919050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61407c8161357d565b82525050565b600061408e8383614073565b60208301905092915050565b6000602082019050919050565b60006140b282614047565b6140bc8185614052565b93506140c783614063565b8060005b838110156140f85781516140df8882614082565b97506140ea8361409a565b9250506001810190506140cb565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561416b578082015181840152602081019050614150565b8381111561417a576000848401525b50505050565b600061418b82614131565b614195818561413c565b93506141a581856020860161414d565b6141ae816133e2565b840191505092915050565b60006141c58383614180565b905092915050565b6000602082019050919050565b60006141e582614105565b6141ef8185614110565b93508360208202850161420185614121565b8060005b8581101561423d578484038952815161421e85826141b9565b9450614229836141cd565b925060208a01995050600181019050614205565b50829750879550505050505092915050565b600061014082019050614265600083018d613b7c565b614272602083018c613b7c565b61427f604083018b613b7c565b61428c606083018a613a2e565b6142996080830189613b7c565b6142a660a0830188613a2e565b6142b360c0830187613a2e565b6142c060e0830186613d12565b8181036101008301526142d381856140a7565b90508181036101208301526142e881846141da565b90509b9a5050505050505050505050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b6000614355602e83613f12565b9150614360826142f9565b604082019050919050565b6000602082019050818103600083015261438481614348565b9050919050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b60006143c76143c26143bd8461438b565b6143a2565b614395565b9050919050565b6143d7816143ac565b82525050565b60006020820190506143f260008301846143ce565b92915050565b600081519050614407816134a5565b92915050565b600060208284031215614423576144226133d3565b5b6000614431848285016143f8565b91505092915050565b7f4f7269756d4d61726b6574706c6163653a206f6e6c7920746f6b656e206f776e60008201527f65722063616e2063616c6c20746869732066756e6374696f6e00000000000000602082015250565b6000614496603983613f12565b91506144a18261443a565b604082019050919050565b600060208201905081810360008301526144c581614489565b9050919050565b60006144d836836137e0565b9050919050565b6000602082840312156144f5576144f46133d3565b5b600061450384828501613532565b91505092915050565b600080fd5b600080fd5b600080fd5b600080833560016020038436030381126145385761453761450c565b5b80840192508235915067ffffffffffffffff82111561455a57614559614511565b5b60208301925060208202360383131561457657614575614516565b5b509250929050565b6000808335600160200384360303811261459b5761459a61450c565b5b80840192508235915067ffffffffffffffff8211156145bd576145bc614511565b5b6020830192506020820236038313156145d9576145d8614516565b5b509250929050565b60006145fc6145f76145f284613507565b6143a2565b6134d1565b9050919050565b61460c816145e1565b82525050565b600080fd5b60006146238385614052565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561465657614655614612565b5b6020830292506146678385846136ac565b82840190509392505050565b6000819050919050565b6000614689838561413c565b93506146968385846136ac565b61469f836133e2565b840190509392505050565b60006146b784848461467d565b90509392505050565b600080fd5b600080fd5b600080fd5b600080833560016020038436030381126146ec576146eb6146ca565b5b83810192508235915060208301925067ffffffffffffffff821115614714576147136146c0565b5b60018202360384131561472a576147296146c5565b5b509250929050565b6000602082019050919050565b600061474b8385614110565b93508360208402850161475d84614673565b8060005b878110156147a357848403895261477882846146cf565b6147838682846146aa565b955061478e84614732565b935060208b019a505050600181019050614761565b50829750879450505050509392505050565b600060e0820190506147ca600083018c613b7c565b6147d7602083018b613b7c565b6147e4604083018a613b7c565b6147f16060830189613a2e565b6147fe6080830188614603565b81810360a0830152614811818688614617565b905081810360c083015261482681848661473f565b90509a9950505050505050505050565b7f4f7269756d4d61726b6574706c6163653a204e6f6e636520657870697265642060008201527f6f72206e6f742075736564207965740000000000000000000000000000000000602082015250565b6000614892602f83613f12565b915061489d82614836565b604082019050919050565b600060208201905081810360008301526148c181614885565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614902826134d1565b915061490d836134d1565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614942576149416148c8565b5b828201905092915050565b600060a0820190506149626000830188613b7c565b61496f6020830187613b7c565b61497c6040830186614603565b818103606083015261498e81856140a7565b905081810360808301526149a281846141da565b90509695505050505050565b60006149bb36848461372b565b905092915050565b60006060820190506149d86000830186613b7c565b6149e56020830185613b7c565b6149f26040830184613d12565b949350505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614a56602683613f12565b9150614a61826149fa565b604082019050919050565b60006020820190508181036000830152614a8581614a49565b9050919050565b600060e082019050614aa1600083018a613b7c565b614aae6020830189613a2e565b614abb6040830188613b7c565b614ac86060830187613b7c565b614ad56080830186613d12565b81810360a0830152614ae781856140a7565b905081810360c0830152614afb81846141da565b905098975050505050505050565b7f4f7269756d4d61726b6574706c6163653a20526f79616c74792070657263656e60008201527f74616765202b206d61726b6574706c616365206665652063616e6e6f7420626560208201527f2067726561746572207468616e20313030250000000000000000000000000000604082015250565b6000614b8b605283613f12565b9150614b9682614b09565b606082019050919050565b60006020820190508181036000830152614bba81614b7e565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204f66666572206e6f74206372656160008201527f7465640000000000000000000000000000000000000000000000000000000000602082015250565b6000614c1d602383613f12565b9150614c2882614bc1565b604082019050919050565b60006020820190508181036000830152614c4c81614c10565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204f6e6c7920626f72726f7765722060008201527f63616e20656e6420612072656e74616c00000000000000000000000000000000602082015250565b6000614caf603083613f12565b9150614cba82614c53565b604082019050919050565b60006020820190508181036000830152614cde81614ca2565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2052656e74616c204f66666572206560008201527f7870697265640000000000000000000000000000000000000000000000000000602082015250565b6000614d41602683613f12565b9150614d4c82614ce5565b604082019050919050565b60006020820190508181036000830152614d7081614d34565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2052656e74616c20656e6465640000600082015250565b6000614dad601e83613f12565b9150614db882614d77565b602082019050919050565b60006020820190508181036000830152614ddc81614da0565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060a082019050614e2760008301886139d7565b614e346020830187613b7c565b614e416040830186613a2e565b614e4e6060830185613b7c565b614e5b6080830184613b7c565b9695505050505050565b6000614e70826134d1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614ea357614ea26148c8565b5b600182019050919050565b6000604082019050614ec36000830185613a2e565b614ed06020830184613b7c565b9392505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614f0d602083613f12565b9150614f1882614ed7565b602082019050919050565b60006020820190508181036000830152614f3c81614f00565b9050919050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b6000614f9f602b83613f12565b9150614faa82614f43565b604082019050919050565b60006020820190508181036000830152614fce81614f92565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204e6f6e63652063616e6e6f74206260008201527f6520300000000000000000000000000000000000000000000000000000000000602082015250565b6000615031602383613f12565b915061503c82614fd5565b604082019050919050565b6000602082019050818103600083015261506081615024565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2053656e64657220616e64204c656e60008201527f646572206d69736d617463680000000000000000000000000000000000000000602082015250565b60006150c3602c83613f12565b91506150ce82615067565b604082019050919050565b600060208201905081810360008301526150f2816150b6565b9050919050565b7f4f7269756d4d61726b6574706c6163653a20726f6c65732073686f756c64206e60008201527f6f7420626520656d707479000000000000000000000000000000000000000000602082015250565b6000615155602b83613f12565b9150615160826150f9565b604082019050919050565b6000602082019050818103600083015261518481615148565b9050919050565b7f4f7269756d4d61726b6574706c6163653a20726f6c657320616e6420726f6c6560008201527f73446174612073686f756c642068617665207468652073616d65206c656e677460208201527f6800000000000000000000000000000000000000000000000000000000000000604082015250565b600061520d604183613f12565b91506152188261518b565b606082019050919050565b6000602082019050818103600083015261523c81615200565b9050919050565b7f4f7269756d4d61726b6574706c6163653a20496e76616c696420646561646c6960008201527f6e65000000000000000000000000000000000000000000000000000000000000602082015250565b600061529f602283613f12565b91506152aa82615243565b604082019050919050565b600060208201905081810360008301526152ce81615292565b9050919050565b7f4f7269756d4d61726b6574706c6163653a206e6f6e636520616c72656164792060008201527f7573656400000000000000000000000000000000000000000000000000000000602082015250565b6000615331602483613f12565b915061533c826152d5565b604082019050919050565b6000602082019050818103600083015261536081615324565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204475726174696f6e20697320677260008201527f6561746572207468616e206d617820646561646c696e65000000000000000000602082015250565b60006153c3603783613f12565b91506153ce82615367565b604082019050919050565b600060208201905081810360008301526153f2816153b6565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204469726563742072656e74616c2060008201527f6e6f742063726561746564000000000000000000000000000000000000000000602082015250565b6000615455602b83613f12565b9150615460826153f9565b604082019050919050565b6000602082019050818103600083015261548481615448565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204469726563742072656e74616c2060008201527f6578706972656400000000000000000000000000000000000000000000000000602082015250565b60006154e7602783613f12565b91506154f28261548b565b604082019050919050565b60006020820190508181036000830152615516816154da565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2053656e64657220616e64204c656e60008201527f6465722f426f72726f776572206d69736d617463680000000000000000000000602082015250565b6000615579603583613f12565b91506155848261551d565b604082019050919050565b600060208201905081810360008301526155a88161556c565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2052656e74616c20616c726561647960008201527f2073746172746564000000000000000000000000000000000000000000000000602082015250565b600061560b602883613f12565b9150615616826155af565b604082019050919050565b6000602082019050818103600083015261563a816155fe565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2053656e646572206973206e6f742060008201527f616c6c6f77656420746f2072656e742074686973204e46540000000000000000602082015250565b600061569d603883613f12565b91506156a882615641565b604082019050919050565b600060208201905081810360008301526156cc81615690565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2065787069726174696f6e2064617460008201527f652069732067726561746572207468616e206f6666657220646561646c696e65602082015250565b600061572f604083613f12565b915061573a826156d3565b604082019050919050565b6000602082019050818103600083015261575e81615722565b9050919050565b6000615770826134d1565b915061577b836134d1565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156157b4576157b36148c8565b5b828202905092915050565b60006060820190506157d46000830186613b7c565b6157e16020830185613b7c565b6157ee6040830184613a2e565b949350505050565b60008151905061580581613e6a565b92915050565b600060208284031215615821576158206133d3565b5b600061582f848285016157f6565b91505092915050565b7f4f7269756d4d61726b6574706c6163653a205472616e73666572206661696c6560008201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b6000615894602183613f12565b915061589f82615838565b604082019050919050565b600060208201905081810360008301526158c381615887565b9050919050565b60006158d5826134d1565b91506158e0836134d1565b9250828210156158f3576158f26148c8565b5b828203905092915050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000615934601483613f12565b915061593f826158fe565b602082019050919050565b6000602082019050818103600083015261596381615927565b9050919050565b61597381613493565b82525050565b615982816134d1565b82525050565b61599181613507565b82525050565b600060e0830160008301516159af6000860182614073565b5060208301516159c2602086018261596a565b5060408301516159d56040860182615979565b5060608301516159e8606086018261596a565b5060808301516159fb608086018261596a565b5060a0830151615a0e60a0860182615988565b5060c083015184820360c0860152615a268282614180565b9150508091505092915050565b60006020820190508181036000830152615a4d8184615997565b905092915050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b6000615a8b601083613f12565b9150615a9682615a55565b602082019050919050565b60006020820190508181036000830152615aba81615a7e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000615afb826134d1565b9150615b06836134d1565b925082615b1657615b15615ac1565b5b82820490509291505056fea26469706673582212200973bc739b71efdb42b64bc0efc2a1c1e5732377b6fb6731cc6692899f316a7164736f6c63430008090033
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101fb5760003560e01c80637df8768e1161011a578063bfcfa66b116100ad578063e9ff836a1161007c578063e9ff836a1461059e578063f2fde38b146105ba578063f41440d9146105d6578063f9603a43146105f2578063fefbb15614610622576101fb565b8063bfcfa66b14610515578063cc3c3dea14610546578063de4e420114610562578063e724604214610580576101fb565b8063993c0f06116100e9578063993c0f061461047d578063a3e8fbce146104ad578063b5639182146104dd578063bf432a09146104f9576101fb565b80637df8768e146103f45780638456cb591461042557806386daff671461042f5780638da5cb5b1461045f576101fb565b806348b90a94116101925780636b7b11ab116101615780636b7b11ab146103945780636e09f420146103b25780636f6aae65146103ce578063715018a6146103ea576101fb565b806348b90a941461030a5780634c255c9714610326578063557d93bb146103445780635c975abb14610376576101fb565b806317450e18116101ce57806317450e18146102845780631794bb3c146102b45780632f553d31146102d05780633f4ba83a14610300576101fb565b80630152dc3b1461020057806303942b261461021c5780630d4995091461023857806311381bcd14610254575b600080fd5b61021a6004803603810190610215919061390e565b61063e565b005b61023660048036038101906102319190613957565b610782565b005b610252600480360381019061024d91906139aa565b610863565b005b61026e6004803603810190610269919061390e565b6108b8565b60405161027b91906139e6565b60405180910390f35b61029e60048036038101906102999190613a01565b610924565b6040516102ab9190613a3d565b60405180910390f35b6102ce60048036038101906102c99190613a58565b6109d3565b005b6102ea60048036038101906102e59190613aab565b610b6d565b6040516102f79190613af3565b60405180910390f35b610308610b8d565b005b610324600480360381019061031f9190613b33565b610b9f565b005b61032e610e6f565b60405161033b9190613a3d565b60405180910390f35b61035e60048036038101906103599190613a01565b610e7c565b60405161036d93929190613b8b565b60405180910390f35b61037e610ee6565b60405161038b9190613af3565b60405180910390f35b61039c610efd565b6040516103a99190613bc2565b60405180910390f35b6103cc60048036038101906103c791906139aa565b610f23565b005b6103e860048036038101906103e39190613cc9565b611091565b005b6103f261135a565b005b61040e60048036038101906104099190613aab565b61136e565b60405161041c929190613d21565b60405180910390f35b61042d6113c6565b005b61044960048036038101906104449190613a01565b6113d8565b6040516104569190613bc2565b60405180910390f35b61046761140b565b6040516104749190613bc2565b60405180910390f35b61049760048036038101906104929190613a01565b611435565b6040516104a49190613bc2565b60405180910390f35b6104c760048036038101906104c29190613d4a565b611559565b6040516104d49190613d8a565b60405180910390f35b6104f760048036038101906104f29190613cc9565b61158f565b005b610513600480360381019061050e9190613da5565b611650565b005b61052f600480360381019061052a9190613a01565b611734565b60405161053d929190613de5565b60405180910390f35b610560600480360381019061055b9190613a01565b611765565b005b61056a6117b1565b6040516105779190613a3d565b60405180910390f35b6105886117b7565b6040516105959190613a3d565b60405180910390f35b6105b860048036038101906105b39190613e0e565b6117c3565b005b6105d460048036038101906105cf9190613a01565b611a29565b005b6105f060048036038101906105eb9190613da5565b611aad565b005b61060c60048036038101906106079190613cc9565b611ac6565b60405161061991906139e6565b60405180910390f35b61063c60048036038101906106379190613e96565b611b1e565b005b6000610649826108b8565b90506106558282611c9c565b6106a9826101000151836040015184606001518560000151609e600087815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ed2565b42609e600083815260200190815260200160002060000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508160600151826040015173ffffffffffffffffffffffffffffffffffffffff168360c001517f64ab891e75e69c9ee4f25bb1f5ba3b22e6034af1ab9e6b7c3563b52baa9579f78560000151609e600087815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16604051610776929190613ee9565b60405180910390a45050565b609b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610852576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084990613f95565b60405180910390fd5b61085e33848484611f94565b505050565b61086b612180565b600081116108ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a590614027565b60405180910390fd5b8060998190555050565b6000816000015182602001518360400151846060015185608001518660a001518760c001518860e001518961010001518a61012001516040516020016109079a9998979695949392919061424f565b604051602081830303815290604052805190602001209050919050565b6000609a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160009054906101000a900460ff16610988576722b1c8c1227a00006109cc565b609a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001545b9050919050565b60008060019054906101000a900460ff16159050808015610a045750600160008054906101000a900460ff1660ff16105b80610a315750610a13306121fe565b158015610a305750600160008054906101000a900460ff1660ff16145b5b610a70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a679061436b565b60405180910390fd5b60016000806101000a81548160ff021916908360ff1602179055508015610aad576001600060016101000a81548160ff0219169083151502179055505b610ab5612221565b610abd61227a565b82609760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081609981905550610b0e84611a29565b8015610b675760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986001604051610b5e91906143dd565b60405180910390a15b50505050565b609c6020528060005260406000206000915054906101000a900460ff1681565b610b95612180565b610b9d6122d3565b565b806040016020810190610bb29190613a01565b81606001358173ffffffffffffffffffffffffffffffffffffffff16636352211e826040518263ffffffff1660e01b8152600401610bf09190613a3d565b60206040518083038186803b158015610c0857600080fd5b505afa158015610c1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c40919061440d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610cad576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca4906144ac565b60405180910390fd5b610cb683612336565b6000610cca84610cc5906144cc565b6108b8565b90508360e0016020810190610cdf91906144df565b609d60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008660c00135815260200190815260200160002060006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506001609c600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508360600135846040016020810190610d9d9190613a01565b73ffffffffffffffffffffffffffffffffffffffff168560c001357f645b3ecd64197738b74753003084af1cf404bf3569e2f7f682b8981cdff1f2b5876000016020810190610dec9190613a01565b886020016020810190610dff9190613a01565b896080016020810190610e129190613a01565b8a60a001358b60e0016020810190610e2a91906144df565b8c806101000190610e3b919061451b565b8e806101200190610e4c919061457e565b604051610e61999897969594939291906147b5565b60405180910390a450505050565b68056bc75e2d6310000081565b609b6020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000606560009054906101000a900460ff16905090565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b42609d60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff1611610fd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fca906148a8565b60405180910390fd5b42609d60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002060006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff16817fceb1a62b6c81ce110df60295368b21991cfac75365f3cb21b27995d37d3ee03360405160405180910390a350565b806000015181602001518173ffffffffffffffffffffffffffffffffffffffff16636352211e826040518263ffffffff1660e01b81526004016110d49190613a3d565b60206040518083038186803b1580156110ec57600080fd5b505afa158015611100573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611124919061440d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611191576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611188906144ac565b60405180910390fd5b61119a83612616565b60006111a584611ac6565b90506000846080015167ffffffffffffffff16426111c391906148f7565b90506001609c600084815260200190815260200160002060006101000a81548160ff0219169083151502179055506040518060400160405280866060015173ffffffffffffffffffffffffffffffffffffffff1681526020018267ffffffffffffffff16815250609e600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055509050506112df8560a001518660c001518760000151886020015189604001518a60600151876001612772565b8460200151856000015173ffffffffffffffffffffffffffffffffffffffff16837f83ec018773fb2d9f2be26dcc9ad0bf29bd25f47a150e354ac942a77e71729978886040015189606001518a608001518b60a001518c60c0015160405161134b95949392919061494d565b60405180910390a45050505050565b611362612180565b61136c60006127ef565b565b609e6020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900467ffffffffffffffff16905082565b6113ce612180565b6113d66128b5565b565b60986020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008073ffffffffffffffffffffffffffffffffffffffff16609860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461152e57609860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611552565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b9050919050565b609d6020528160005260406000206020528060005260406000206000915091509054906101000a900467ffffffffffffffff1681565b600061159a82611ac6565b90506115a68282612918565b42609e600083815260200190815260200160002060000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506116048260a001518360000151846020015185604001518660600151611ed2565b816040015173ffffffffffffffffffffffffffffffffffffffff16817fc955c36f0072545b860e915eb3f3ca5e1a61046cde3c9a01d237ae2cdd6df44d60405160405180910390a35050565b611658612180565b80609860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fe4439c77c292ccd794f87871827c1bac9053f5900ac32b62c734678ddd1d01c760405160405180910390a35050565b609a6020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16905082565b61176d612180565b80609760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60995481565b6722b1c8c1227a000081565b60008167ffffffffffffffff16426117db91906148f7565b90506117e78382612a9e565b61182e8360400160208101906117fd9190613a01565b8460800160208101906118109190613a01565b8560a00135858760000160208101906118299190613a01565b612d29565b6118d283806101000190611842919061451b565b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505084806101200190611893919061457e565b9061189e91906149ae565b8560400160208101906118b19190613a01565b86606001358760000160208101906118c99190613a01565b33876000612772565b60405180604001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018267ffffffffffffffff16815250609e600061191d86611918906144cc565b6108b8565b815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555090505082606001358360400160208101906119bc9190613a01565b73ffffffffffffffffffffffffffffffffffffffff168460c001357f6ac7cb5ec310cf58d38b9b4b1b9dc4314b1540a5eb85c468fe90a80d27673871866000016020810190611a0b9190613a01565b3386604051611a1c939291906149c3565b60405180910390a4505050565b611a31612180565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611aa1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a9890614a6c565b60405180910390fd5b611aaa816127ef565b50565b611ab5612180565b611ac28183600080611f94565b5050565b6000816000015182602001518360400151846060015185608001518660a001518760c00151604051602001611b019796959493929190614a8c565b604051602081830303815290604052805190602001209050919050565b611b26612180565b6000609b60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010154905068056bc75e2d631000008382611b8391906148f7565b10611bc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bba90614ba1565b60405180910390fd5b6040518060400160405280848152602001831515815250609a60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff0219169083151502179055509050508373ffffffffffffffffffffffffffffffffffffffff167fc60e6f659e43dc4ad63d5a27cea2b5bd7b775ea5a9f1e8f4ba2dd4566809b5098484604051611c8e929190613de5565b60405180910390a250505050565b609c600082815260200190815260200160002060009054906101000a900460ff16611cfc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cf390614c33565b60405180910390fd5b609e600082815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611da0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d9790614cc5565b60405180910390fd5b42609d6000846000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008460c00151815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff1611611e58576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e4f90614d57565b60405180910390fd5b42609e600083815260200190815260200160002060000160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1611611ece576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ec590614dc3565b60405180910390fd5b5050565b6000611edd85611435565b905060005b8651811015611f8b578173ffffffffffffffffffffffffffffffffffffffff1663a9c39982888381518110611f1a57611f19614de3565b5b6020026020010151888888886040518663ffffffff1660e01b8152600401611f46959493929190614e12565b600060405180830381600087803b158015611f6057600080fd5b505af1158015611f74573d6000803e3d6000fd5b505050508080611f8390614e65565b915050611ee2565b50505050505050565b68056bc75e2d63100000611fa784610924565b83611fb291906148f7565b10611ff2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fe990614ba1565b60405180910390fd5b60405180606001604052808573ffffffffffffffffffffffffffffffffffffffff1681526020018381526020018273ffffffffffffffffffffffffffffffffffffffff16815250609b60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f48ad8485693b9973ead8f2419c47217555f7b8197a637de45e68b507779aee778484604051612172929190614eae565b60405180910390a350505050565b6121886130c6565b73ffffffffffffffffffffffffffffffffffffffff166121a661140b565b73ffffffffffffffffffffffffffffffffffffffff16146121fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121f390614f23565b60405180910390fd5b565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600060019054906101000a900460ff16612270576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161226790614fb5565b60405180910390fd5b6122786130ce565b565b600060019054906101000a900460ff166122c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122c090614fb5565b60405180910390fd5b6122d161313a565b565b6122db61319b565b6000606560006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61231f6130c6565b60405161232c9190613bc2565b60405180910390a1565b60008160c00135141561237e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161237590615047565b60405180910390fd5b8060000160208101906123919190613a01565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146123fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123f5906150d9565b60405180910390fd5b600081806101000190612411919061451b565b905011612453576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161244a9061516b565b60405180910390fd5b80806101200190612464919061457e565b905081806101000190612477919061451b565b9050146124b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124b090615223565b60405180910390fd5b609954426124c791906148f7565b8160e00160208101906124da91906144df565b67ffffffffffffffff161115801561250d5750428160e001602081019061250191906144df565b67ffffffffffffffff16115b61254c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612543906152b5565b60405180910390fd5b6000609d60008360000160208101906125659190613a01565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008360c00135815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff1614612613576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161260a90615347565b60405180910390fd5b50565b609954816080015167ffffffffffffffff161115612669576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612660906153d9565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146126db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126d2906150d9565b60405180910390fd5b60008160a001515111612723576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161271a9061516b565b60405180910390fd5b8060c00151518160a00151511461276f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161276690615223565b60405180910390fd5b50565b600061277d87611435565b905060005b89518110156127e3576127d08a82815181106127a1576127a0614de3565b5b602002602001015189898989898f88815181106127c1576127c0614de3565b5b6020026020010151898b6131e4565b80806127db90614e65565b915050612782565b50505050505050505050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6128bd613355565b6001606560006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586129016130c6565b60405161290e9190613bc2565b60405180910390a1565b609c600082815260200190815260200160002060009054906101000a900460ff16612978576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161296f9061546b565b60405180910390fd5b42609e600083815260200190815260200160002060000160149054906101000a900467ffffffffffffffff1667ffffffffffffffff16116129ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129e5906154fd565b60405180910390fd5b816040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480612a5b5750816060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b612a9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a919061558f565b60405180910390fd5b5050565b6000612ab283612aad906144cc565b6108b8565b905042609e600083815260200190815260200160002060000160149054906101000a900467ffffffffffffffff1667ffffffffffffffff161115612b2b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b2290615621565b60405180910390fd5b609c600082815260200190815260200160002060009054906101000a900460ff16612b8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b8290614c33565b60405180910390fd5b826020016020810190612b9e9190613a01565b73ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff161480612c155750826020016020810190612be69190613a01565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b612c54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c4b906156b3565b60405180910390fd5b8167ffffffffffffffff16609d6000856000016020810190612c769190613a01565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008560c00135815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff1611612d24576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d1b90615745565b60405180910390fd5b505050565b60008267ffffffffffffffff1684612d419190615765565b90506000811415612d5257506130bf565b6000612d6682612d6189610924565b61339f565b90506000811115612e47578573ffffffffffffffffffffffffffffffffffffffff166323b872dd33612d9661140b565b846040518463ffffffff1660e01b8152600401612db5939291906157bf565b602060405180830381600087803b158015612dcf57600080fd5b505af1158015612de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e07919061580b565b612e46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e3d906158aa565b60405180910390fd5b5b6000612e9583609b60008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015461339f565b90506000811115612fd1578673ffffffffffffffffffffffffffffffffffffffff166323b872dd33609b60008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518463ffffffff1660e01b8152600401612f3f939291906157bf565b602060405180830381600087803b158015612f5957600080fd5b505af1158015612f6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f91919061580b565b612fd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612fc7906158aa565b60405180910390fd5b5b6000828285612fe091906158ca565b612fea91906158ca565b90508773ffffffffffffffffffffffffffffffffffffffff166323b872dd3387846040518463ffffffff1660e01b8152600401613029939291906157bf565b602060405180830381600087803b15801561304357600080fd5b505af1158015613057573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061307b919061580b565b6130ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130b1906158aa565b60405180910390fd5b505050505b5050505050565b600033905090565b600060019054906101000a900460ff1661311d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161311490614fb5565b60405180910390fd5b6000606560006101000a81548160ff021916908315150217905550565b600060019054906101000a900460ff16613189576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161318090614fb5565b60405180910390fd5b6131996131946130c6565b6127ef565b565b6131a3610ee6565b6131e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016131d99061594a565b60405180910390fd5b565b60006040518060e001604052808b81526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018667ffffffffffffffff16815260200185815250905081156132dd578273ffffffffffffffffffffffffffffffffffffffff166344c722cf826040518263ffffffff1660e01b81526004016132a69190615a33565b600060405180830381600087803b1580156132c057600080fd5b505af11580156132d4573d6000803e3d6000fd5b50505050613349565b8273ffffffffffffffffffffffffffffffffffffffff16639760a9e1826040518263ffffffff1660e01b81526004016133169190615a33565b600060405180830381600087803b15801561333057600080fd5b505af1158015613344573d6000803e3d6000fd5b505050505b50505050505050505050565b61335d610ee6565b1561339d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161339490615aa1565b60405180910390fd5b565b600068056bc75e2d6310000082846133b79190615765565b6133c19190615af0565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61342b826133e2565b810181811067ffffffffffffffff8211171561344a576134496133f3565b5b80604052505050565b600061345d6133c9565b90506134698282613422565b919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061349e82613473565b9050919050565b6134ae81613493565b81146134b957600080fd5b50565b6000813590506134cb816134a5565b92915050565b6000819050919050565b6134e4816134d1565b81146134ef57600080fd5b50565b600081359050613501816134db565b92915050565b600067ffffffffffffffff82169050919050565b61352481613507565b811461352f57600080fd5b50565b6000813590506135418161351b565b92915050565b600080fd5b600067ffffffffffffffff821115613567576135666133f3565b5b602082029050602081019050919050565b600080fd5b6000819050919050565b6135908161357d565b811461359b57600080fd5b50565b6000813590506135ad81613587565b92915050565b60006135c66135c18461354c565b613453565b905080838252602082019050602084028301858111156135e9576135e8613578565b5b835b8181101561361257806135fe888261359e565b8452602084019350506020810190506135eb565b5050509392505050565b600082601f83011261363157613630613547565b5b81356136418482602086016135b3565b91505092915050565b600067ffffffffffffffff821115613665576136646133f3565b5b602082029050602081019050919050565b600080fd5b600067ffffffffffffffff821115613696576136956133f3565b5b61369f826133e2565b9050602081019050919050565b82818337600083830152505050565b60006136ce6136c98461367b565b613453565b9050828152602081018484840111156136ea576136e9613676565b5b6136f58482856136ac565b509392505050565b600082601f83011261371257613711613547565b5b81356137228482602086016136bb565b91505092915050565b600061373e6137398461364a565b613453565b9050808382526020820190506020840283018581111561376157613760613578565b5b835b818110156137a857803567ffffffffffffffff81111561378657613785613547565b5b80860161379389826136fd565b85526020850194505050602081019050613763565b5050509392505050565b600082601f8301126137c7576137c6613547565b5b81356137d784826020860161372b565b91505092915050565b600061014082840312156137f7576137f66133dd565b5b613802610140613453565b90506000613812848285016134bc565b6000830152506020613826848285016134bc565b602083015250604061383a848285016134bc565b604083015250606061384e848285016134f2565b6060830152506080613862848285016134bc565b60808301525060a0613876848285016134f2565b60a08301525060c061388a848285016134f2565b60c08301525060e061389e84828501613532565b60e08301525061010082013567ffffffffffffffff8111156138c3576138c261346e565b5b6138cf8482850161361c565b6101008301525061012082013567ffffffffffffffff8111156138f5576138f461346e565b5b613901848285016137b2565b6101208301525092915050565b600060208284031215613924576139236133d3565b5b600082013567ffffffffffffffff811115613942576139416133d8565b5b61394e848285016137e0565b91505092915050565b6000806000606084860312156139705761396f6133d3565b5b600061397e868287016134bc565b935050602061398f868287016134f2565b92505060406139a0868287016134bc565b9150509250925092565b6000602082840312156139c0576139bf6133d3565b5b60006139ce848285016134f2565b91505092915050565b6139e08161357d565b82525050565b60006020820190506139fb60008301846139d7565b92915050565b600060208284031215613a1757613a166133d3565b5b6000613a25848285016134bc565b91505092915050565b613a37816134d1565b82525050565b6000602082019050613a526000830184613a2e565b92915050565b600080600060608486031215613a7157613a706133d3565b5b6000613a7f868287016134bc565b9350506020613a90868287016134bc565b9250506040613aa1868287016134f2565b9150509250925092565b600060208284031215613ac157613ac06133d3565b5b6000613acf8482850161359e565b91505092915050565b60008115159050919050565b613aed81613ad8565b82525050565b6000602082019050613b086000830184613ae4565b92915050565b600080fd5b60006101408284031215613b2a57613b29613b0e565b5b81905092915050565b600060208284031215613b4957613b486133d3565b5b600082013567ffffffffffffffff811115613b6757613b666133d8565b5b613b7384828501613b13565b91505092915050565b613b8581613493565b82525050565b6000606082019050613ba06000830186613b7c565b613bad6020830185613a2e565b613bba6040830184613b7c565b949350505050565b6000602082019050613bd76000830184613b7c565b92915050565b600060e08284031215613bf357613bf26133dd565b5b613bfd60e0613453565b90506000613c0d848285016134bc565b6000830152506020613c21848285016134f2565b6020830152506040613c35848285016134bc565b6040830152506060613c49848285016134bc565b6060830152506080613c5d84828501613532565b60808301525060a082013567ffffffffffffffff811115613c8157613c8061346e565b5b613c8d8482850161361c565b60a08301525060c082013567ffffffffffffffff811115613cb157613cb061346e565b5b613cbd848285016137b2565b60c08301525092915050565b600060208284031215613cdf57613cde6133d3565b5b600082013567ffffffffffffffff811115613cfd57613cfc6133d8565b5b613d0984828501613bdd565b91505092915050565b613d1b81613507565b82525050565b6000604082019050613d366000830185613b7c565b613d436020830184613d12565b9392505050565b60008060408385031215613d6157613d606133d3565b5b6000613d6f858286016134bc565b9250506020613d80858286016134f2565b9150509250929050565b6000602082019050613d9f6000830184613d12565b92915050565b60008060408385031215613dbc57613dbb6133d3565b5b6000613dca858286016134bc565b9250506020613ddb858286016134bc565b9150509250929050565b6000604082019050613dfa6000830185613a2e565b613e076020830184613ae4565b9392505050565b60008060408385031215613e2557613e246133d3565b5b600083013567ffffffffffffffff811115613e4357613e426133d8565b5b613e4f85828601613b13565b9250506020613e6085828601613532565b9150509250929050565b613e7381613ad8565b8114613e7e57600080fd5b50565b600081359050613e9081613e6a565b92915050565b600080600060608486031215613eaf57613eae6133d3565b5b6000613ebd868287016134bc565b9350506020613ece868287016134f2565b9250506040613edf86828701613e81565b9150509250925092565b6000604082019050613efe6000830185613b7c565b613f0b6020830184613b7c565b9392505050565b600082825260208201905092915050565b7f4f7269756d4d61726b6574706c6163653a204f6e6c792063726561746f72206360008201527f616e2073657420726f79616c747920696e666f00000000000000000000000000602082015250565b6000613f7f603383613f12565b9150613f8a82613f23565b604082019050919050565b60006020820190508181036000830152613fae81613f72565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204d617820646561646c696e65207360008201527f686f756c642062652067726561746572207468616e2030000000000000000000602082015250565b6000614011603783613f12565b915061401c82613fb5565b604082019050919050565b6000602082019050818103600083015261404081614004565b9050919050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61407c8161357d565b82525050565b600061408e8383614073565b60208301905092915050565b6000602082019050919050565b60006140b282614047565b6140bc8185614052565b93506140c783614063565b8060005b838110156140f85781516140df8882614082565b97506140ea8361409a565b9250506001810190506140cb565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561416b578082015181840152602081019050614150565b8381111561417a576000848401525b50505050565b600061418b82614131565b614195818561413c565b93506141a581856020860161414d565b6141ae816133e2565b840191505092915050565b60006141c58383614180565b905092915050565b6000602082019050919050565b60006141e582614105565b6141ef8185614110565b93508360208202850161420185614121565b8060005b8581101561423d578484038952815161421e85826141b9565b9450614229836141cd565b925060208a01995050600181019050614205565b50829750879550505050505092915050565b600061014082019050614265600083018d613b7c565b614272602083018c613b7c565b61427f604083018b613b7c565b61428c606083018a613a2e565b6142996080830189613b7c565b6142a660a0830188613a2e565b6142b360c0830187613a2e565b6142c060e0830186613d12565b8181036101008301526142d381856140a7565b90508181036101208301526142e881846141da565b90509b9a5050505050505050505050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b6000614355602e83613f12565b9150614360826142f9565b604082019050919050565b6000602082019050818103600083015261438481614348565b9050919050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b60006143c76143c26143bd8461438b565b6143a2565b614395565b9050919050565b6143d7816143ac565b82525050565b60006020820190506143f260008301846143ce565b92915050565b600081519050614407816134a5565b92915050565b600060208284031215614423576144226133d3565b5b6000614431848285016143f8565b91505092915050565b7f4f7269756d4d61726b6574706c6163653a206f6e6c7920746f6b656e206f776e60008201527f65722063616e2063616c6c20746869732066756e6374696f6e00000000000000602082015250565b6000614496603983613f12565b91506144a18261443a565b604082019050919050565b600060208201905081810360008301526144c581614489565b9050919050565b60006144d836836137e0565b9050919050565b6000602082840312156144f5576144f46133d3565b5b600061450384828501613532565b91505092915050565b600080fd5b600080fd5b600080fd5b600080833560016020038436030381126145385761453761450c565b5b80840192508235915067ffffffffffffffff82111561455a57614559614511565b5b60208301925060208202360383131561457657614575614516565b5b509250929050565b6000808335600160200384360303811261459b5761459a61450c565b5b80840192508235915067ffffffffffffffff8211156145bd576145bc614511565b5b6020830192506020820236038313156145d9576145d8614516565b5b509250929050565b60006145fc6145f76145f284613507565b6143a2565b6134d1565b9050919050565b61460c816145e1565b82525050565b600080fd5b60006146238385614052565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561465657614655614612565b5b6020830292506146678385846136ac565b82840190509392505050565b6000819050919050565b6000614689838561413c565b93506146968385846136ac565b61469f836133e2565b840190509392505050565b60006146b784848461467d565b90509392505050565b600080fd5b600080fd5b600080fd5b600080833560016020038436030381126146ec576146eb6146ca565b5b83810192508235915060208301925067ffffffffffffffff821115614714576147136146c0565b5b60018202360384131561472a576147296146c5565b5b509250929050565b6000602082019050919050565b600061474b8385614110565b93508360208402850161475d84614673565b8060005b878110156147a357848403895261477882846146cf565b6147838682846146aa565b955061478e84614732565b935060208b019a505050600181019050614761565b50829750879450505050509392505050565b600060e0820190506147ca600083018c613b7c565b6147d7602083018b613b7c565b6147e4604083018a613b7c565b6147f16060830189613a2e565b6147fe6080830188614603565b81810360a0830152614811818688614617565b905081810360c083015261482681848661473f565b90509a9950505050505050505050565b7f4f7269756d4d61726b6574706c6163653a204e6f6e636520657870697265642060008201527f6f72206e6f742075736564207965740000000000000000000000000000000000602082015250565b6000614892602f83613f12565b915061489d82614836565b604082019050919050565b600060208201905081810360008301526148c181614885565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614902826134d1565b915061490d836134d1565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614942576149416148c8565b5b828201905092915050565b600060a0820190506149626000830188613b7c565b61496f6020830187613b7c565b61497c6040830186614603565b818103606083015261498e81856140a7565b905081810360808301526149a281846141da565b90509695505050505050565b60006149bb36848461372b565b905092915050565b60006060820190506149d86000830186613b7c565b6149e56020830185613b7c565b6149f26040830184613d12565b949350505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000614a56602683613f12565b9150614a61826149fa565b604082019050919050565b60006020820190508181036000830152614a8581614a49565b9050919050565b600060e082019050614aa1600083018a613b7c565b614aae6020830189613a2e565b614abb6040830188613b7c565b614ac86060830187613b7c565b614ad56080830186613d12565b81810360a0830152614ae781856140a7565b905081810360c0830152614afb81846141da565b905098975050505050505050565b7f4f7269756d4d61726b6574706c6163653a20526f79616c74792070657263656e60008201527f74616765202b206d61726b6574706c616365206665652063616e6e6f7420626560208201527f2067726561746572207468616e20313030250000000000000000000000000000604082015250565b6000614b8b605283613f12565b9150614b9682614b09565b606082019050919050565b60006020820190508181036000830152614bba81614b7e565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204f66666572206e6f74206372656160008201527f7465640000000000000000000000000000000000000000000000000000000000602082015250565b6000614c1d602383613f12565b9150614c2882614bc1565b604082019050919050565b60006020820190508181036000830152614c4c81614c10565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204f6e6c7920626f72726f7765722060008201527f63616e20656e6420612072656e74616c00000000000000000000000000000000602082015250565b6000614caf603083613f12565b9150614cba82614c53565b604082019050919050565b60006020820190508181036000830152614cde81614ca2565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2052656e74616c204f66666572206560008201527f7870697265640000000000000000000000000000000000000000000000000000602082015250565b6000614d41602683613f12565b9150614d4c82614ce5565b604082019050919050565b60006020820190508181036000830152614d7081614d34565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2052656e74616c20656e6465640000600082015250565b6000614dad601e83613f12565b9150614db882614d77565b602082019050919050565b60006020820190508181036000830152614ddc81614da0565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060a082019050614e2760008301886139d7565b614e346020830187613b7c565b614e416040830186613a2e565b614e4e6060830185613b7c565b614e5b6080830184613b7c565b9695505050505050565b6000614e70826134d1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614ea357614ea26148c8565b5b600182019050919050565b6000604082019050614ec36000830185613a2e565b614ed06020830184613b7c565b9392505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614f0d602083613f12565b9150614f1882614ed7565b602082019050919050565b60006020820190508181036000830152614f3c81614f00565b9050919050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b6000614f9f602b83613f12565b9150614faa82614f43565b604082019050919050565b60006020820190508181036000830152614fce81614f92565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204e6f6e63652063616e6e6f74206260008201527f6520300000000000000000000000000000000000000000000000000000000000602082015250565b6000615031602383613f12565b915061503c82614fd5565b604082019050919050565b6000602082019050818103600083015261506081615024565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2053656e64657220616e64204c656e60008201527f646572206d69736d617463680000000000000000000000000000000000000000602082015250565b60006150c3602c83613f12565b91506150ce82615067565b604082019050919050565b600060208201905081810360008301526150f2816150b6565b9050919050565b7f4f7269756d4d61726b6574706c6163653a20726f6c65732073686f756c64206e60008201527f6f7420626520656d707479000000000000000000000000000000000000000000602082015250565b6000615155602b83613f12565b9150615160826150f9565b604082019050919050565b6000602082019050818103600083015261518481615148565b9050919050565b7f4f7269756d4d61726b6574706c6163653a20726f6c657320616e6420726f6c6560008201527f73446174612073686f756c642068617665207468652073616d65206c656e677460208201527f6800000000000000000000000000000000000000000000000000000000000000604082015250565b600061520d604183613f12565b91506152188261518b565b606082019050919050565b6000602082019050818103600083015261523c81615200565b9050919050565b7f4f7269756d4d61726b6574706c6163653a20496e76616c696420646561646c6960008201527f6e65000000000000000000000000000000000000000000000000000000000000602082015250565b600061529f602283613f12565b91506152aa82615243565b604082019050919050565b600060208201905081810360008301526152ce81615292565b9050919050565b7f4f7269756d4d61726b6574706c6163653a206e6f6e636520616c72656164792060008201527f7573656400000000000000000000000000000000000000000000000000000000602082015250565b6000615331602483613f12565b915061533c826152d5565b604082019050919050565b6000602082019050818103600083015261536081615324565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204475726174696f6e20697320677260008201527f6561746572207468616e206d617820646561646c696e65000000000000000000602082015250565b60006153c3603783613f12565b91506153ce82615367565b604082019050919050565b600060208201905081810360008301526153f2816153b6565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204469726563742072656e74616c2060008201527f6e6f742063726561746564000000000000000000000000000000000000000000602082015250565b6000615455602b83613f12565b9150615460826153f9565b604082019050919050565b6000602082019050818103600083015261548481615448565b9050919050565b7f4f7269756d4d61726b6574706c6163653a204469726563742072656e74616c2060008201527f6578706972656400000000000000000000000000000000000000000000000000602082015250565b60006154e7602783613f12565b91506154f28261548b565b604082019050919050565b60006020820190508181036000830152615516816154da565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2053656e64657220616e64204c656e60008201527f6465722f426f72726f776572206d69736d617463680000000000000000000000602082015250565b6000615579603583613f12565b91506155848261551d565b604082019050919050565b600060208201905081810360008301526155a88161556c565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2052656e74616c20616c726561647960008201527f2073746172746564000000000000000000000000000000000000000000000000602082015250565b600061560b602883613f12565b9150615616826155af565b604082019050919050565b6000602082019050818103600083015261563a816155fe565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2053656e646572206973206e6f742060008201527f616c6c6f77656420746f2072656e742074686973204e46540000000000000000602082015250565b600061569d603883613f12565b91506156a882615641565b604082019050919050565b600060208201905081810360008301526156cc81615690565b9050919050565b7f4f7269756d4d61726b6574706c6163653a2065787069726174696f6e2064617460008201527f652069732067726561746572207468616e206f6666657220646561646c696e65602082015250565b600061572f604083613f12565b915061573a826156d3565b604082019050919050565b6000602082019050818103600083015261575e81615722565b9050919050565b6000615770826134d1565b915061577b836134d1565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156157b4576157b36148c8565b5b828202905092915050565b60006060820190506157d46000830186613b7c565b6157e16020830185613b7c565b6157ee6040830184613a2e565b949350505050565b60008151905061580581613e6a565b92915050565b600060208284031215615821576158206133d3565b5b600061582f848285016157f6565b91505092915050565b7f4f7269756d4d61726b6574706c6163653a205472616e73666572206661696c6560008201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b6000615894602183613f12565b915061589f82615838565b604082019050919050565b600060208201905081810360008301526158c381615887565b9050919050565b60006158d5826134d1565b91506158e0836134d1565b9250828210156158f3576158f26148c8565b5b828203905092915050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000615934601483613f12565b915061593f826158fe565b602082019050919050565b6000602082019050818103600083015261596381615927565b9050919050565b61597381613493565b82525050565b615982816134d1565b82525050565b61599181613507565b82525050565b600060e0830160008301516159af6000860182614073565b5060208301516159c2602086018261596a565b5060408301516159d56040860182615979565b5060608301516159e8606086018261596a565b5060808301516159fb608086018261596a565b5060a0830151615a0e60a0860182615988565b5060c083015184820360c0860152615a268282614180565b9150508091505092915050565b60006020820190508181036000830152615a4d8184615997565b905092915050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b6000615a8b601083613f12565b9150615a9682615a55565b602082019050919050565b60006020820190508181036000830152615aba81615a7e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000615afb826134d1565b9150615b06836134d1565b925082615b1657615b15615ac1565b5b82820490509291505056fea26469706673582212200973bc739b71efdb42b64bc0efc2a1c1e5732377b6fb6731cc6692899f316a7164736f6c63430008090033