def fastqIteratorComplex(fn, useMutableString=False, verbose=False):
  """
    A generator function which yields FastqSequence objects read from a file or
    stream. This iterator can handle fastq files that have their sequence
    and/or their quality data split across multiple lines (i.e. there are
    newline characters in the sequence and quality strings).

    :param fn:                 A file-like stream or a string; if this is a
                               string, it's treated as a filename specifying
                               the location of an input fastq file, else it's
                               treated as a file-like object, which must have a
                               readline() method.
    :param useMustableString:  if True, construct sequences from lists of
                               chars, rather than python string objects, to
                               allow more efficient editing. Use with caution.
    :param verbose:            if True, print messages on progress to stderr.
    :param debug:              if True, print debugging messages to stderr.
    :param sanger:             if True, assume quality scores are in sanger
                               format. Otherwise, assume they're in Illumina
                               format.
  """
  fh = fn
  if type(fh).__name__ == "str":
    fh = open(fh)
  prevLine = None

  # try to get an idea of how much data we have...
  pind = None
  if verbose:
    try:
      totalLines = linesInFile(fh.name)
      pind = ProgressIndicator(totalToDo=totalLines,
                               messagePrefix="completed",
                               messageSuffix="of processing "
                                             + fh.name)
    except AttributeError:
      sys.stderr.write("fastqIterator -- warning: "
                       + "unable to show progress for stream")
      verbose = False

  while True:
    # either we have a sequence header left over from the
    # prev call, or we need to read a new one from the file...
    # try to do that now
    name, prevLine = fastq_complex_parse_seq_header(fh, prevLine,
                                                    pind, verbose)

    # read lines until we hit a qual header --> this is our sequence data
    seqdata, line = fastq_complex_parse_seq(fh, pind, verbose)

    # <line> is now a qual header, keep reading until we see
    # a sequence header.. or we run out of lines.. this is our quality data
    qualdata, line, prevLine = fastq_complex_parse_qual(fh, line, prevLine,
                                                        verbose, pind)

    # package it all up..
    yield NGSRead(seqdata, name, qualdata, useMutableString)
    if verbose:
      pind.showProgress()

    # remember where we stopped for next call, or finish
    prevLine = line
    if prevLine == "":
      break
A generator function which yields FastqSequence objects read from a file or
    stream. This iterator can handle fastq files that have their sequence
    and/or their quality data split across multiple lines (i.e. there are
    newline characters in the sequence and quality strings).

    :param fn:                 A file-like stream or a string; if this is a
                               string, it's treated as a filename specifying
                               the location of an input fastq file, else it's
                               treated as a file-like object, which must have a
                               readline() method.
    :param useMustableString:  if True, construct sequences from lists of
                               chars, rather than python string objects, to
                               allow more efficient editing. Use with caution.
    :param verbose:            if True, print messages on progress to stderr.
    :param debug:              if True, print debugging messages to stderr.
    :param sanger:             if True, assume quality scores are in sanger
                               format. Otherwise, assume they're in Illumina
                               format.