A more straitfoward calculation of the context-specific errors 
    relative to the target

    :returns: matrix of observed contexts and values
    :rtype: matrix of [before][after][reference]{types} with types being any base or a deletion.

def get_context_target_errors(self):
    """A more straitfoward calculation of the context-specific errors 
    relative to the target

    :returns: matrix of observed contexts and values
    :rtype: matrix of [before][after][reference]{types} with types being any base or a deletion.

    """
    if self._context_target_errors:  return self._context_target_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._target_errors)-1):

      tobs = self._target_errors[i].get_observable()
      tunobs = self._target_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._target_errors[i-1].get_base()
      t = self._target_errors[i].get_base()
      tafter = self._target_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'][qb] += op
      elif otype[0] == 'match':
        tb = otype[2][0][0]
        qb = otype[2][1][0]
        r[tbefore][tafter][t]['types'][qb] += float(1)
      elif otype[0] == 'deletion':
        tb = otype[2][0][0]
        qb = otype[2][1][0]
        r[tbefore][tafter][t]['types']['-'] += op
        r[tbefore][tafter][t]['types'][qb] += (1-op)
      # make sure our insertion can't be bigger than 1
      hp_insert_before = 0
      hp_insert_after = 0
      if otype[0] == 'insertion':
        tb = otype[2][0][0]
        qb = otype[2][1][0]
        r[tbefore][tb]['-']['types'][qb] += op/2
        r[tb][tafter]['-']['types'][qb] += op/2
        #homopolymer ... so we do have the correct base
        r[tbefore][tafter][t]['types'][qb] += 1

      # now take care of total insertions
      total_bp = 0
      total_ap = 0
      if before:
        qb = before[2][1][0]
        r[tbefore][t]['-']['types'][qb] += bp
      if after:
        qb = after[2][1][0]
        r[t][tafter]['-']['types'][qb] += ap
      #r[tbefore][t]['-']['types'][qb] += total_bp+(1-total_bp)*hp_insert_before
      #r[t][tafter]['-']['types'][qb] += total_ap+(1-total_ap)*hp_insert_after

      ##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