docs: def parse_raxml(handle):
      """Parse RAxML's summary output.
  
      *handle* should be an open file handle containing the RAxML
      output.  It is parsed and a dictionary returned.
      """
      s = ''.join(handle.readlines())
      result = {}
      try_set_fields(result, r'(?P<program>RAxML version [0-9.]+)', s)
      try_set_fields(result, r'(?P<datatype>DNA|RNA|AA)', s)
      result['empirical_frequencies'] = (
          result['datatype'] != 'AA' or
          re.search('empirical base frequencies', s, re.IGNORECASE) is not None)
      try_set_fields(result, r'Substitution Matrix: (?P<subs_model>\w+)', s)
      rates = {}
      if result['datatype'] != 'AA':
          try_set_fields(rates,
                         (r"rates\[0\] ac ag at cg ct gt: "
                          r"(?P<ac>[0-9.]+) (?P<ag>[0-9.]+) (?P<at>[0-9.]+) "
                          r"(?P<cg>[0-9.]+) (?P<ct>[0-9.]+) (?P<gt>[0-9.]+)"),
                         s, hook=float)
          try_set_fields(rates, r'rate A <-> C: (?P<ac>[0-9.]+)', s, hook=float)
          try_set_fields(rates, r'rate A <-> G: (?P<ag>[0-9.]+)', s, hook=float)
          try_set_fields(rates, r'rate A <-> T: (?P<at>[0-9.]+)', s, hook=float)
          try_set_fields(rates, r'rate C <-> G: (?P<cg>[0-9.]+)', s, hook=float)
          try_set_fields(rates, r'rate C <-> T: (?P<ct>[0-9.]+)', s, hook=float)
          try_set_fields(rates, r'rate G <-> T: (?P<gt>[0-9.]+)', s, hook=float)
          if len(rates) > 0:
              result['subs_rates'] = rates
      result['gamma'] = {'n_cats': 4}
      try_set_fields(result['gamma'],
                     r"alpha[\[\]0-9]*: (?P<alpha>[0-9.]+)", s, hook=float)
      result['ras_model'] = 'gamma'
      return result