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 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)