docs: def _fillAndTraceback(self, table):
          """
          Perform Local Alignment according to Smith-Waterman Algorithm.
          Fills the table and then traces back from the highest score.
          NB left = deletion and up = insertion wrt seq1
          """
          # Fill
          max_score = 0
          max_row = 0
          max_col = 0
  
          for row in range(1, len(self.seq2Seq) + 1):
              for col in range(1, len(self.seq1Seq) + 1):
                  # Calculate match score
                  letter1 = self.seq1Seq[col - 1]
                  letter2 = self.seq2Seq[row - 1]
                  if letter1 == letter2:
                      diagonal_score = (table[row - 1][col - 1]['score'] +
                                        self.match)
                  else:
                      diagonal_score = (table[row - 1][col - 1]['score'] +
                                        self.mismatch)
  
                  ins_run = table[row - 1][col]['ins']
                  del_run = table[row][col - 1]['del']
  
                  # Calculate gap scores ensuring extension is not > 0
                  if table[row - 1][col]['ins'] <= 0:
                      ins_score = table[row - 1][col]['score'] + self.gapOpen
                  else:
                      if self.gapExtend + ins_run * self.gapExtendDecay <= 0.0:
                          ins_score = (table[row - 1][col]['score'] +
                                       self.gapExtend +
                                       ins_run * self.gapExtendDecay)
                      else:
                          ins_score = table[row - 1][col]['score']
  
                  if table[row - 1][col]['del'] <= 0:
                      del_score = table[row][col - 1]['score'] + self.gapOpen
                  else:
                      if self.gapExtend + del_run * self.gapExtendDecay <= 0.0:
                          del_score = (table[row][col - 1]['score'] +
                                       self.gapExtend +
                                       del_run * self.gapExtendDecay)
                      else:
                          del_score = table[row][col - 1]['score']
  
                  # Choose best score
                  if diagonal_score <= 0 and ins_score <= 0 and del_score <= 0:
                      table[row][col] = {'score': 0, 'pointer': None, 'ins': 0,
                                         'del': 0}
                  else:
                      if diagonal_score >= ins_score:
                          if diagonal_score >= del_score:  # diag lef/up
                              diagonal = {'score': diagonal_score,
                                          'pointer': 'diagonal', 'ins': 0,
                                          'del': 0}
                              table[row][col] = diagonal
                          else:  # lef diag/up
                              deletion = {'score': del_score, 'pointer': 'del',
                                          'ins': 0, 'del': del_run + 1}
                              table[row][col] = deletion
                      else:  # up diag
                          if ins_score >= del_score:  # up diag/lef
                              insertion = {'score': ins_score, 'pointer': 'ins',
                                           'ins': ins_run + 1, 'del': 0}
                              table[row][col] = insertion
                          else:  # lef up diag
                              deletion = {'score': del_score, 'pointer': 'del',
                                          'ins': 0, 'del': del_run + 1}
                              table[row][col] = deletion
  
                  # Set max score - is this the best way of getting max score
                  # considering how the for loop iterates through the matrix?
                  if table[row][col]['score'] >= max_score:
                      max_row = row
                      max_col = col
                      max_score = table[row][col]['score']
  
          # Traceback
          indexes = {'max_row': max_row, 'max_col': max_col}
          align1 = ''
          align2 = ''
          align = ''
  
          current_row = max_row
          current_col = max_col
  
          while True:
              arrow = table[current_row][current_col]['pointer']
              if arrow is None:
                  min_row = current_row + 1
                  min_col = current_col + 1
                  break
              elif arrow == 'diagonal':
                  align1 += self.seq1Seq[current_col - 1]
                  align2 += self.seq2Seq[current_row - 1]
                  if self.seq1Seq[current_col - 1] == self.seq2Seq[
                          current_row - 1]:
                      align += '|'
                  else:
                      align += ' '
                  current_row -= 1
                  current_col -= 1
              elif arrow == 'del':
                  align1 += self.seq1Seq[current_col - 1]
                  align2 += '-'
                  align += ' '
                  current_col -= 1
              elif arrow == 'ins':
                  align1 += '-'
                  align2 += self.seq2Seq[current_row - 1]
                  align += ' '
                  current_row -= 1
              else:
                  raise ValueError('Invalid pointer: %s' % arrow)
  
          indexes['min_row'] = min_row
          indexes['min_col'] = min_col
          align1 = align1[::-1]
          align2 = align2[::-1]
          align = align[::-1]
  
          if len(align1) != len(align2):
              raise ValueError(
                  'Lengths of locally aligned sequences differ (%d != %d).' % (
                      len(align1), len(align2)))
  
          return ([align1, align, align2], indexes)