docs: 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