docs: def maf_iterator(fn, index_friendly=False,
                   yield_class=MultipleSequenceAlignment, yield_kw_args={},
                   verbose=False):
    """
    Iterate of MAF format file and yield <yield_class> objects for each block.
  
    MAF files are arranged in blocks. Each block is a multiple alignment. Within
    a block, the first character of a line indicates what kind of line it is:
  
    a -- key-value pair meta data for block; one per block, should be first line
    s -- a sequence line; see __build_sequence() for details.
    i -- always come after s lines, and contain information about the context of
         the sequence; see __annotate_sequence_with_context() for details.
    e -- indicates that there is no aligning sequence for a species, but that
         there are blocks before and after this one that do align. See
         __build_unknown_sequence() for details.
    q -- quality information about an aligned base in a species. See
         __annotate_sequence_with_quality()
  
    :param yield_class:   yield objects returned by this function/constructor;
                          must accept key-word args of 'sequences' and
                          'meta_data' which are list and dictionary respectively.
                          Default is MultipleSequenceAlignment
    :param yield_kw_args: extra keyword args to pass to 'yield_class'
    """
  
    try:
      fh = open(fn)
    except (TypeError):
      fh = fn
    if index_friendly:
      fh = iter(fh.readline, '')
  
    sequences = []
    meta_data = {}
    for line in fh:
      line = line.strip()
      if line == "" or line[0] == "#":
        continue
      parts = line.split()
      line_type = parts[0].strip()
      if line_type == A_LINE:
        if sequences != []:
          meta_data[SEQ_ORDER_KEY] = [s.name for s in sequences]
          kw_args = merge_dictionaries({"sequences": sequences,
                                        "meta_data": meta_data}, yield_kw_args)
          yield yield_class(**kw_args)
        sequences = []
        meta_data = {}
        for i in range(1, len(parts)):
          assert(parts[i].count("=") == 1)
          piv = parts[i].find("=")
          meta_data[parts[i][:piv]] = parts[i][piv + 1:]
      elif line_type == S_LINE:
        sequences.append(__build_sequence(parts))
      elif line_type == I_LINE:
        if len(sequences) < 1:
          raise MAFError("found information line with no preceeding sequence " +
                         "in block")
        __annotate_sequence_with_context(sequences[-1], parts)
      elif line_type == E_LINE:
        sequences.append(__build_unknown_sequence(parts))
      elif line_type == Q_LINE:
        if len(sequences) < 1:
          raise MAFError("found quality line with no preceeding sequence in " +
                         "block")
        __annotate_sequence_with_quality(sequences[-1], parts)
      else:
        raise MAFError("Unknown type of MAF line: " + line)
  
    # don't forget to yield the final block
    if sequences != []:
      meta_data[SEQ_ORDER_KEY] = [s.name for s in sequences]
      kw_args = merge_dictionaries({"sequences": sequences,
                                    "meta_data": meta_data},
                                   yield_kw_args)
      yield yield_class(**kw_args)