docs: def get_context_query_errors(self):
      """A more straitfoward calculation of the context-specific errors 
      relative to the query
  
      :returns: matrix of observed contexts and values
      :rtype: matrix of [before][after][query]{types} with types being any base or a deletion.
  
      """
      if self._context_query_errors:  return self._context_query_errors
      if len(self._query_errors) < 3: return {}
      nts = ['A','C','G','T']
      poss = ['A','C','G','T','-']
      r = {}
      for i in nts:
        if i not in r:  r[i] = {}
        for j in nts:
          if j not in r[i]: r[i][j] = {}
          for k in poss:
            if k not in r[i][j]: 
              r[i][j][k] = {}
              r[i][j][k]['types'] = {}
              r[i][j][k]['total'] = 0
            for l in poss:
              if l not in r[i][j][k]['types']: r[i][j][k]['types'][l] = 0
      # now r is initialized
      for i in range(1,len(self._query_errors)-1):
  
        tobs = self._query_errors[i].get_observable()
        tunobs = self._query_errors[i].get_unobservable()
        otype = tobs.get_type()
        op = tobs.get_error_probability()
        before = tunobs.get_before_type()
        bp = tunobs.get_before_probability()
        after = tunobs.get_after_type()
        ap = tunobs.get_after_probability()
        if otype[2][0][0] == 'N': continue
        if otype[2][1][0] == 'N': continue
        if before:
          if before[2][0][0] == 'N': continue
          if before[2][1][0] == 'N': continue
        if after:
          if after[2][0][0] == 'N': continue
          if after[2][1][0] == 'N': continue
  
        tbefore = self._query_errors[i-1].get_base()
        t = self._query_errors[i].get_base()
        tafter = self._query_errors[i+1].get_base()
  
        if tbefore == 'N' or tafter == 'N' or t == 'N': continue
        r[tbefore][t]['-']['total'] += 0.5
        r[t][tafter]['-']['total'] += 0.5
        r[tbefore][tafter][t]['total'] += 1
  
        # We know we made an observation
        if otype[0] == 'mismatch':
          tb = otype[2][0][0]
          qb = otype[2][1][0]
          r[tbefore][tafter][t]['types'][tb] += op
        elif otype[0] == 'match':
          tb = otype[2][0][0]
          qb = otype[2][1][0]
          r[tbefore][tafter][t]['types'][tb] += float(1)
        elif otype[0] == 'insertion':
          tb = otype[2][0][0]
          qb = otype[2][1][0]
          r[tbefore][tafter][t]['types']['-'] += op
          r[tbefore][tafter][t]['types'][tb] += (1-op)
        # make sure our deletion can't be bigger than 1
        hp_deletion_before = 0
        hp_deletion_after = 0
        if otype[0] == 'deletion':
          tb = otype[2][0][0]
          qb = otype[2][1][0]
          r[tbefore][tb]['-']['types'][tb] += op/2
          r[tb][tafter]['-']['types'][tb] += op/2
          #homopolymer ... so we do have the correct base
          r[tbefore][tafter][t]['types'][tb] += 1
  
        # now take care of total deletions
        if before:
          tb = before[2][0][0]
          r[tbefore][t]['-']['types'][tb] += bp
        if after:
          tb = after[2][0][0]
          r[t][tafter]['-']['types'][tb] += ap
  
        ##type = self._target_errors[i].get_type()
        #p = self._target_errors[i].get_error_probability()
        #if p > 0:
        #  if type[0] not in r[tbefore][t][tafter]['types']:
        #    r[tbefore][t][tafter]['types'][type[0]] = 0
        #  r[tbefore][t][tafter]['types'][type[0]] += p
        #r[tbefore][t][tafter]['total']+=1
      for b in r:
        for a in r:
          val = sum([r[b][a]['-']['types'][q] for q in nts])
          r[b][a]['-']['types']['-'] = r[b][a]['-']['total'] - val
      return r