docs: def _generate_sequences_for_texts(self, l1, t1, l2, t2, ngrams):
          """Generates and outputs aligned sequences for the texts `t1` and `t2`
          from `ngrams`.
  
          :param l1: label of first witness
          :type l1: `str`
          :param t1: text content of first witness
          :type t1: `str`
          :param l2: label of second witness
          :type l2: `str`
          :param t2: text content of second witness
          :type t2: `str`
          :param ngrams: n-grams to base sequences on
          :type ngrams: `list` of `str`
  
          """
          # self._subsitutes is gradually populated as each text is
          # processed, so this needs to be regenerated each time.
          self._reverse_substitutes = dict((v, k) for k, v in
                                           self._substitutes.items())
          sequences = []
          # Keep track of spans within each text that have been covered
          # by an aligned sequence, to ensure that they aren't reported
          # more than once. The first sub-list contains span indices for
          # text t1, the second for t2.
          covered_spans = [[], []]
          for ngram in ngrams:
              sequences.extend(self._generate_sequences_for_ngram(
                  t1, t2, ngram, covered_spans))
          if sequences:
              sequences.sort(key=lambda x: x.start_index)
              context = {'l1': l1, 'l2': l2, 'sequences': sequences}
              report_name = '{}-{}.html'.format(l1, l2)
              os.makedirs(self._output_dir, exist_ok=True)
              self._write(context, self._output_dir, report_name)