abstract contract KinectAirBaseERC721 is
    Context,
    AccessControlEnumerable,
    SplitWithdrawable,
    IERC2981,
    ERC721Enumerable,
    ERC721Holder,
    ERC721Pausable,
    Ownable
{
    uint8 public immutable TOKENS_RESERVED;
    uint256 internal tokenIdCounter;

    bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE');
    bytes32 public constant PAUSER_ROLE = keccak256('PAUSER_ROLE');
    bytes32 public constant OPERATOR_ROLE = keccak256('OPERATOR_ROLE');

    /// @dev Verify that the given token ID exists, or revert
    modifier mustExist(uint256 _tokenId) {
        require(_exists(_tokenId), 'KAOA/must-exist');
        _;
    }

    modifier onlyMinters() {
        require(hasRole(MINTER_ROLE, _msgSender()), 'KAOA/minter-role-only');
        _;
    }

    modifier onlyOperators() {
        require(hasRole(OPERATOR_ROLE, _msgSender()), 'KAOA/operator-role-only');
        _;
    }

    /**
     * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the
     * account that deploys the contract.
     *
     * Token URIs will be autogenerated based on `baseURI` and their token IDs.
     * See {ERC721-tokenURI}.
     */
    constructor(
        string memory name,
        string memory symbol,
        uint8 reserved
    ) ERC721(name, symbol) {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setupRole(MINTER_ROLE, _msgSender());
        _setupRole(PAUSER_ROLE, _msgSender());
        _setupRole(OPERATOR_ROLE, _msgSender());

        // this value is immutable
        TOKENS_RESERVED = reserved;
        // start our counter after the reserved tokens
        tokenIdCounter = reserved;
    }

    /**
     * @dev Pauses all token transfers.
     *
     * See {ERC721Pausable} and {Pausable-_pause}.
     *
     * Requirements:
     *
     * - the caller must have the `PAUSER_ROLE`.
     */
    function pause() public virtual {
        require(hasRole(PAUSER_ROLE, _msgSender()), 'ERC721Pausable: must have pauser role to pause');
        _pause();
    }

    /**
     * @dev Unpauses all token transfers.
     *
     * See {ERC721Pausable} and {Pausable-_unpause}.
     *
     * Requirements:
     *
     * - the caller must have the `PAUSER_ROLE`.
     */
    function unpause() public virtual {
        require(hasRole(PAUSER_ROLE, _msgSender()), 'ERC721Pausable: must have pauser role to unpause');
        _unpause();
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override(ERC721Enumerable, ERC721Pausable) {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(AccessControlEnumerable, ERC721, ERC721Enumerable, IERC165)
        returns (bool)
    {
        return type(IERC2981).interfaceId == interfaceId || super.supportsInterface(interfaceId);
    }
}
/**
 * @dev {ERC721} token, including:
 *
 *  - a minter role that allows for token minting (creation)
 *  - a pauser role that allows to stop all token transfers
 *  - an operator role for updating token metadata
 *  - token ID autogeneration
 *
 * This contract uses {AccessControl} to lock permissioned functions using the
 * different roles - head to its documentation for details.
 *
 * The account that deploys the contract will be granted the minter and pauser
 * roles, as well as the default admin role, which will let it grant both minter
 * and pauser roles to other accounts.
 */
function supportsInterface(bytes4 interfaceId)
    public
    view
    virtual
    override(AccessControlEnumerable, ERC721, ERC721Enumerable, IERC165)
    returns (bool)
{
    return type(IERC2981).interfaceId == interfaceId || super.supportsInterface(interfaceId);
}

/**
 * @dev See {IERC165-supportsInterface}.
 */