function diff_cleanupMerge(diffs, fix_unicode) {
   diffs.push([DIFF_EQUAL, '']);  // Add a dummy entry at the end.
   var pointer = 0;
   var count_delete = 0;
   var count_insert = 0;
   var text_delete = '';
   var text_insert = '';
   var commonlength;
   while (pointer < diffs.length) {
     if (pointer < diffs.length - 1 && !diffs[pointer][1]) {
       diffs.splice(pointer, 1);
       continue;
     }
     switch (diffs[pointer][0]) {
       case DIFF_INSERT:
 
         count_insert++;
         text_insert += diffs[pointer][1];
         pointer++;
         break;
       case DIFF_DELETE:
         count_delete++;
         text_delete += diffs[pointer][1];
         pointer++;
         break;
       case DIFF_EQUAL:
         var previous_equality = pointer - count_insert - count_delete - 1;
         if (fix_unicode) {
           // prevent splitting of unicode surrogate pairs.  when fix_unicode is true,
           // we assume that the old and new text in the diff are complete and correct
           // unicode-encoded JS strings, but the tuple boundaries may fall between
           // surrogate pairs.  we fix this by shaving off stray surrogates from the end
           // of the previous equality and the beginning of this equality.  this may create
           // empty equalities or a common prefix or suffix.  for example, if AB and AC are
           // emojis, `[[0, 'A'], [-1, 'BA'], [0, 'C']]` would turn into deleting 'ABAC' and
           // inserting 'AC', and then the common suffix 'AC' will be eliminated.  in this
           // particular case, both equalities go away, we absorb any previous inequalities,
           // and we keep scanning for the next equality before rewriting the tuples.
           if (previous_equality >= 0 && ends_with_pair_start(diffs[previous_equality][1])) {
             var stray = diffs[previous_equality][1].slice(-1);
             diffs[previous_equality][1] = diffs[previous_equality][1].slice(0, -1);
             text_delete = stray + text_delete;
             text_insert = stray + text_insert;
             if (!diffs[previous_equality][1]) {
               // emptied out previous equality, so delete it and include previous delete/insert
               diffs.splice(previous_equality, 1);
               pointer--;
               var k = previous_equality - 1;
               if (diffs[k] && diffs[k][0] === DIFF_INSERT) {
                 count_insert++;
                 text_insert = diffs[k][1] + text_insert;
                 k--;
               }
               if (diffs[k] && diffs[k][0] === DIFF_DELETE) {
                 count_delete++;
                 text_delete = diffs[k][1] + text_delete;
                 k--;
               }
               previous_equality = k;
             }
           }
           if (starts_with_pair_end(diffs[pointer][1])) {
             var stray = diffs[pointer][1].charAt(0);
             diffs[pointer][1] = diffs[pointer][1].slice(1);
             text_delete += stray;
             text_insert += stray;
           }
         }
         if (pointer < diffs.length - 1 && !diffs[pointer][1]) {
           // for empty equality not at end, wait for next equality
           diffs.splice(pointer, 1);
           break;
         }
         if (text_delete.length > 0 || text_insert.length > 0) {
           // note that diff_commonPrefix and diff_commonSuffix are unicode-aware
           if (text_delete.length > 0 && text_insert.length > 0) {
             // Factor out any common prefixes.
             commonlength = diff_commonPrefix(text_insert, text_delete);
             if (commonlength !== 0) {
               if (previous_equality >= 0) {
                 diffs[previous_equality][1] += text_insert.substring(0, commonlength);
               } else {
                 diffs.splice(0, 0, [DIFF_EQUAL, text_insert.substring(0, commonlength)]);
                 pointer++;
               }
               text_insert = text_insert.substring(commonlength);
               text_delete = text_delete.substring(commonlength);
             }
             // Factor out any common suffixes.
             commonlength = diff_commonSuffix(text_insert, text_delete);
             if (commonlength !== 0) {
               diffs[pointer][1] =
                 text_insert.substring(text_insert.length - commonlength) + diffs[pointer][1];
               text_insert = text_insert.substring(0, text_insert.length - commonlength);
               text_delete = text_delete.substring(0, text_delete.length - commonlength);
             }
           }
           // Delete the offending records and add the merged ones.
           var n = count_insert + count_delete;
           if (text_delete.length === 0 && text_insert.length === 0) {
             diffs.splice(pointer - n, n);
             pointer = pointer - n;
           } else if (text_delete.length === 0) {
             diffs.splice(pointer - n, n, [DIFF_INSERT, text_insert]);
             pointer = pointer - n + 1;
           } else if (text_insert.length === 0) {
             diffs.splice(pointer - n, n, [DIFF_DELETE, text_delete]);
             pointer = pointer - n + 1;
           } else {
             diffs.splice(pointer - n, n, [DIFF_DELETE, text_delete], [DIFF_INSERT, text_insert]);
             pointer = pointer - n + 2;
           }
         }
         if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) {
           // Merge this equality with the previous one.
           diffs[pointer - 1][1] += diffs[pointer][1];
           diffs.splice(pointer, 1);
         } else {
           pointer++;
         }
         count_insert = 0;
         count_delete = 0;
         text_delete = '';
         text_insert = '';
         break;
     }
   }
   if (diffs[diffs.length - 1][1] === '') {
     diffs.pop();  // Remove the dummy entry at the end.
   }
 
   // Second pass: look for single edits surrounded on both sides by equalities
   // which can be shifted sideways to eliminate an equality.
   // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
   var changes = false;
   pointer = 1;
   // Intentionally ignore the first and last element (don't need checking).
   while (pointer < diffs.length - 1) {
     if (diffs[pointer - 1][0] === DIFF_EQUAL &&
       diffs[pointer + 1][0] === DIFF_EQUAL) {
       // This is a single edit surrounded by equalities.
       if (diffs[pointer][1].substring(diffs[pointer][1].length -
         diffs[pointer - 1][1].length) === diffs[pointer - 1][1]) {
         // Shift the edit over the previous equality.
         diffs[pointer][1] = diffs[pointer - 1][1] +
           diffs[pointer][1].substring(0, diffs[pointer][1].length -
             diffs[pointer - 1][1].length);
         diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
         diffs.splice(pointer - 1, 1);
         changes = true;
       } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) ==
         diffs[pointer + 1][1]) {
         // Shift the edit over the next equality.
         diffs[pointer - 1][1] += diffs[pointer + 1][1];
         diffs[pointer][1] =
           diffs[pointer][1].substring(diffs[pointer + 1][1].length) +
           diffs[pointer + 1][1];
         diffs.splice(pointer + 1, 1);
         changes = true;
       }
     }
     pointer++;
   }
   // If shifts were made, the diff needs reordering and another shift sweep.
   if (changes) {
     diff_cleanupMerge(diffs, fix_unicode);
   }
 }
Reorder and merge like edit sections.  Merge equalities.
Any edit section can move as long as it doesn't cross an equality.
@param {Array} diffs Array of diff tuples.
@param {boolean} fix_unicode Whether to normalize to a unicode-correct diff