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)