Contract Address Details

0xAb8E668acD4FEF935D5DfD869410bf8704688a53

Contract Name
OriumMarketplace
Creator
0x04c8c6–706806 at 0xa5f3a6–21a985
Balance
0 TCRO
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
26342119
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