docs: def from_repeat_masker_string(s):
    """
    Parse a RepeatMasker string. This format is white-space separated and has
    15 columns. The first 11 are invariably as follows:
  
    +----------------------+---------+-----------+----------------------------+
    |     Description      |  Type   |  Example  | Notes                      |
    +======================+=========+===========+============================+
    | alignment score      | int (?) |  463      |                            |
    +----------------------+---------+-----------+----------------------------+
    | percent divergence   | float   | 1.3       |                            |
    +----------------------+---------+-----------+----------------------------+
    | percent deletions    | float   | 0.6       |                            |
    +----------------------+---------+-----------+----------------------------+
    | percent insertions   | float   | 1.7       |                            |
    +----------------------+---------+-----------+----------------------------+
    | query seq. name      | string  | chr1      |                            |
    +----------------------+---------+-----------+----------------------------+
    | query seq. start     | int     | 10001     | always pos. strand coords  |
    +----------------------+---------+-----------+----------------------------+
    | query seq. end       | int     | 10468     | always pos. strand         |
    +----------------------+---------+-----------+----------------------------+
    | query seq. remaining | int     | (105)     | always in parenthesis,     |
    |                      |         |           | always negative strand     |
    |                      |         |           | coords. Bases left in      |
    |                      |         |           | query sequence before end  |
    |                      |         |           | (alt. can be interpreted   |
    |                      |         |           | as negative strand coord   |
    |                      |         |           | of genomic end coord).     |
    +----------------------+---------+-----------+----------------------------+
    | strand               | char    | C         | either + or C              |
    |                      |         |           | (complement); this refers  |
    |                      |         |           | to whether the match is    |
    |                      |         |           | to the consensus or the    |
    |                      |         |           | rev. comp. of it.          |
    +----------------------+---------+-----------+----------------------------+
    | repeat name          | string  | AluJo     |                            |
    +----------------------+---------+-----------+----------------------------+
    | repeat family        | string  | SINE/Alu  |                            |
    +----------------------+---------+-----------+----------------------------+
  
    The next three depend on whether the genomic sequence was a match to the
    consensus sequence, or to the reverse complement of the consensus sequence.
    In the former case, they are as follows:
  
    +------------------------+-------+-----------+-----------------------------+
    |     Description        | Type  |  Example  | Notes                       |
    +========================+=======+===========+=============================+
    | consensus match start  | int   |   45      | awlays pos strand           |
    +------------------------+-------+-----------+-----------------------------+
    | consensus match end    | int   |   60      | always pos strand;          |
    |                        |       |           | end >= start; it is         |
    |                        |       |           | inclusive of the final      |
    |                        |       |           | coordinate (unlike e.g.     |
    |                        |       |           | UCSC coords)                |
    +------------------------+-------+-----------+-----------------------------+
    | consensus match remain | (int) |  (40)     | for '+' match, always       |
    |                        |       |           | negative strand coords. Num |
    |                        |       |           | of bases after match before |
    |                        |       |           | end of consensus. (Alt. can |
    |                        |       |           | be considered the negative  |
    |                        |       |           | strand coords of the match  |
    |                        |       |           | end in consensus seq.)      |
    +------------------------+-------+-----------+-----------------------------+
  
    In the latter case, they have this interpretation:
  
    +------------------------+-------+-----------+-----------------------------+
    |     Description        | Type  |  Example  | Notes                       |
    +========================+=======+===========+=============================+
    | consensus match before | (int) | (10)      | always neg. strand (always  |
    |                        |       |           | parens); number of bases    |
    |                        |       |           | before start of match on    |
    |                        |       |           | negative strand (alt. can   |
    |                        |       |           | be interpreted as the       |
    |                        |       |           | negative strand coordinates |
    |                        |       |           | of the match start)         |
    +------------------------+-------+-----------+-----------------------------+
    | consensus match start  | int   | 345       | start of match in pos.      |
    |                        |       |           | strand coords.              |
    +------------------------+-------+-----------+-----------------------------+
    | consensus match end    | int   | 143       | end of match in pos. strand |
    |                        |       |           | coords. Because match is on |
    |                        |       |           | neg. strand, 'start' is     |
    |                        |       |           | always >= end.              |
    +------------------------+-------+-----------+-----------------------------+
  
    The final column should be an ID, but I have noticed this is sometimes
    missing. We don't use all of the above fields, and we convert everything into
    positive strand coords where start < end always.
  
    :param s: string representation of a retrotransposon occurrence in
              RepeatMasker format.
    :return: Retrotransposon object corresponding to the string s.
    """
    parts = s.split()
  
    if len(parts) != 15 and len(parts) != 14:
      raise RetrotransposonError("incorrectly formated RepeatMasker entry: " + s)
  
    # get rid of those pesky parentheses
    for i in [11, 12, 13]:
      parts[i] = parts[i].strip()
      if parts[i][0] == "(":
        parts[i] = parts[i][1:]
      if parts[i][-1] == ")":
        parts[i] = parts[i][0:-1]
  
    # the first 11, invariant columns...
    # score = float(parts[0])  -- we don't use this
    # p_div = float(parts[1])  -- we don't use this
    # p_del = float(parts[2])  -- we don't use this
    # p_ins = float(parts[3])  -- we don't use this
    q_seq = parts[4].strip()
    q_seq_start = int(parts[5])
    q_seq_end = int(parts[6]) + 1
    # left_qseq = parts[7].strip() -- we don't use this
    strand = "-" if parts[8].strip() in COMPLEMENT_CHARS else "+"
    repeat_name = parts[9].strip()
    repeat_family = parts[10].strip()
  
    # the three columns the define match location in the consensus
    con_pos_start = int(parts[11]) if strand is "+" else int(parts[13])
    con_pos_end = int(parts[12]) + 1
    con_pos_left = int(parts[13]) if strand is "+" else int(parts[11])
  
    # might get ID, mgiht not -- its sometimes missing.
    repeat_id = int(parts[14].strip()) if len(parts) == 15 else None
  
    # we can compute the length of the consensus using the 'leftover' index
    con_seq_len = con_pos_end + con_pos_left
  
    rt = Retrotransposon(repeat_name, repeat_family)
    return RetrotransposonOccurrence(q_seq, q_seq_start, q_seq_end, strand,
                                     con_pos_start, con_pos_end, con_seq_len,
                                     rt, uniq_id=repeat_id)