contract Issuable is Ownable, SupportsInterfaceWithLookup {
  bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");

  /**
   * @dev Throws if called by any account that's not a issuer.
   */
  modifier onlyIssuer() {
    require(isIssuer(_msgSender()), 'Issuable: caller is not the issuer');
    _;
  }

  modifier onlyOwnerOrIssuer() {
    require(_msgSender() == owner() || isIssuer(_msgSender()), 'Issuable: caller is not the issuer or the owner');
    _;
  }

  /**
   * @dev getter to determine if address has issuer role
   */
  function isIssuer(address _operator) public view returns (bool) {
    return hasRole(ISSUER_ROLE, _operator);
  }

  /**
   * @dev add a new issuer address
   * @param _operator address
   */
  function addIssuer(address _operator) public onlyOwner {
    grantRole(ISSUER_ROLE, _operator);
  }

  /**
   * @dev remove an address from issuers
   * @param _operator address
   */
  function removeIssuer(address _operator) public onlyOwner {
    revokeRole(ISSUER_ROLE, _operator);
  }

  /**
   * @dev Allows the current issuer to transfer his role to a newIssuer.
   * @param _newIssuer The address to transfer the issuer role to.
   */
  function transferIssuer(address _newIssuer) public onlyIssuer {
    require(_newIssuer != address(0));
    revokeRole(ISSUER_ROLE, _msgSender());
    grantRole(ISSUER_ROLE, _newIssuer);
  }

}
/**
 * @title Issuable
 * @dev The Issuable contract defines the issuer role who can perform certain kind of actions
 * even if he is not the owner.
 * An issuer can transfer his role to a new address.
 */
function isIssuer(address _operator) public view returns (bool) {
  return hasRole(ISSUER_ROLE, _operator);
}

/**
 * @dev getter to determine if address has issuer role
 */