docs: def parse(fp):
      """
      Parse the contents of the `~io.IOBase.readline`-supporting file-like object
      ``fp`` as a simple line-oriented ``.properties`` file and return a
      generator of ``(key, value, original_lines)`` triples for every entry in
      ``fp`` (including duplicate keys) in order of occurrence.  The third
      element of each triple is the concatenation of the unmodified lines in
      ``fp`` (including trailing newlines) from which the key and value were
      extracted.  The generator also includes comments and blank/all-whitespace
      lines found in ``fp``, one triple per line, with the first two elements of
      the triples set to `None`.  This is the only way to extract comments from a
      ``.properties`` file with this library.
  
      ``fp`` may be either a text or binary filehandle, with or without universal
      newlines enabled.  If it is a binary filehandle, its contents are decoded
      as Latin-1.
  
      .. versionchanged:: 0.5.0
          Invalid ``\\uXXXX`` escape sequences will now cause an
          `InvalidUEscapeError` to be raised
  
      :param fp: the file from which to read the ``.properties`` document
      :type fp: file-like object
      :rtype: generator of triples of text strings
      :raises InvalidUEscapeError: if an invalid ``\\uXXXX`` escape sequence
          occurs in the input
      """
      def lineiter():
          while True:
              ln = fp.readline()
              if isinstance(ln, binary_type):
                  ln = ln.decode('iso-8859-1')
              if ln == '':
                  return
              for l in ascii_splitlines(ln):
                  yield l
      liter = lineiter()
      for source in liter:
          line = source
          if re.match(r'^[ \t\f]*(?:[#!]|\r?\n?$)', line):
              yield (None, None, source)
              continue
          line = line.lstrip(' \t\f').rstrip('\r\n')
          while re.search(r'(?<!\\)(?:\\\\)*\\$', line):
              line = line[:-1]
              nextline = next(liter, '')
              source += nextline
              line += nextline.lstrip(' \t\f').rstrip('\r\n')
          if line == '':  # series of otherwise-blank lines with continuations
              yield (None, None, source)
              continue
          m = re.search(r'(?<!\\)(?:\\\\)*([ \t\f]*[=:]|[ \t\f])[ \t\f]*', line)
          if m:
              yield (unescape(line[:m.start(1)]),unescape(line[m.end():]),source)
          else:
              yield (unescape(line), '', source)