Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Basic makePatch and applyPatch functionality added

  • Loading branch information...
commit 9d77f881967e527a33255e007bc2960cc00bdc5d 0 parents
Charlotte Gore authored April 21, 2012
BIN  .DS_Store
Binary file not shown
1  .gitignore
... ...
@@ -0,0 +1 @@
  1
+node_modules
22  LICENSE
... ...
@@ -0,0 +1,22 @@
  1
+Copyright (c) 2012 Charlotte Gore
  2
+
  3
+Permission is hereby granted, free of charge, to any person
  4
+obtaining a copy of this software and associated documentation
  5
+files (the "Software"), to deal in the Software without
  6
+restriction, including without limitation the rights to use,
  7
+copy, modify, merge, publish, distribute, sublicense, and/or sell
  8
+copies of the Software, and to permit persons to whom the
  9
+Software is furnished to do so, subject to the following
  10
+conditions:
  11
+
  12
+The above copyright notice and this permission notice shall be
  13
+included in all copies or substantial portions of the Software.
  14
+
  15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  17
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  19
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22
+OTHER DEALINGS IN THE SOFTWARE.
5  Makefile
... ...
@@ -0,0 +1,5 @@
  1
+test:
  2
+	./node_modules/.bin/mocha \
  3
+		--reporter list
  4
+
  5
+.PHONY: test
0  README.md
Source Rendered
No changes.
2,205  lib/diff_match_patch.js
... ...
@@ -0,0 +1,2205 @@
  1
+/**
  2
+ * Diff Match and Patch
  3
+ *
  4
+ * Copyright 2006 Google Inc.
  5
+ * http://code.google.com/p/google-diff-match-patch/
  6
+ *
  7
+ * Licensed under the Apache License, Version 2.0 (the "License");
  8
+ * you may not use this file except in compliance with the License.
  9
+ * You may obtain a copy of the License at
  10
+ *
  11
+ *   http://www.apache.org/licenses/LICENSE-2.0
  12
+ *
  13
+ * Unless required by applicable law or agreed to in writing, software
  14
+ * distributed under the License is distributed on an "AS IS" BASIS,
  15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16
+ * See the License for the specific language governing permissions and
  17
+ * limitations under the License.
  18
+ */
  19
+
  20
+/**
  21
+ * @fileoverview Computes the difference between two texts to create a patch.
  22
+ * Applies the patch onto another text, allowing for errors.
  23
+ * @author fraser@google.com (Neil Fraser)
  24
+ */
  25
+
  26
+/**
  27
+ * Class containing the diff, match and patch methods.
  28
+ * @constructor
  29
+ */
  30
+function diff_match_patch() {
  31
+
  32
+  // Defaults.
  33
+  // Redefine these in your program to override the defaults.
  34
+
  35
+  // Number of seconds to map a diff before giving up (0 for infinity).
  36
+  this.Diff_Timeout = 1.0;
  37
+  // Cost of an empty edit operation in terms of edit characters.
  38
+  this.Diff_EditCost = 4;
  39
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
  40
+  this.Match_Threshold = 0.5;
  41
+  // How far to search for a match (0 = exact location, 1000+ = broad match).
  42
+  // A match this many characters away from the expected location will add
  43
+  // 1.0 to the score (0.0 is a perfect match).
  44
+  this.Match_Distance = 1000;
  45
+  // When deleting a large block of text (over ~64 characters), how close do
  46
+  // the contents have to be to match the expected contents. (0.0 = perfection,
  47
+  // 1.0 = very loose).  Note that Match_Threshold controls how closely the
  48
+  // end points of a delete need to match.
  49
+  this.Patch_DeleteThreshold = 0.5;
  50
+  // Chunk size for context length.
  51
+  this.Patch_Margin = 4;
  52
+
  53
+  // The number of bits in an int.
  54
+  this.Match_MaxBits = 32;
  55
+}
  56
+
  57
+
  58
+//  DIFF FUNCTIONS
  59
+
  60
+
  61
+/**
  62
+ * The data structure representing a diff is an array of tuples:
  63
+ * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
  64
+ * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
  65
+ */
  66
+var DIFF_DELETE = -1;
  67
+var DIFF_INSERT = 1;
  68
+var DIFF_EQUAL = 0;
  69
+
  70
+/** @typedef {{0: number, 1: string}} */
  71
+diff_match_patch.Diff;
  72
+
  73
+
  74
+/**
  75
+ * Find the differences between two texts.  Simplifies the problem by stripping
  76
+ * any common prefix or suffix off the texts before diffing.
  77
+ * @param {string} text1 Old string to be diffed.
  78
+ * @param {string} text2 New string to be diffed.
  79
+ * @param {boolean=} opt_checklines Optional speedup flag. If present and false,
  80
+ *     then don't run a line-level diff first to identify the changed areas.
  81
+ *     Defaults to true, which does a faster, slightly less optimal diff.
  82
+ * @param {number} opt_deadline Optional time when the diff should be complete
  83
+ *     by.  Used internally for recursive calls.  Users should set DiffTimeout
  84
+ *     instead.
  85
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  86
+ */
  87
+diff_match_patch.prototype.diff_main = function(text1, text2, opt_checklines,
  88
+    opt_deadline) {
  89
+  // Set a deadline by which time the diff must be complete.
  90
+  if (typeof opt_deadline == 'undefined') {
  91
+    if (this.Diff_Timeout <= 0) {
  92
+      opt_deadline = Number.MAX_VALUE;
  93
+    } else {
  94
+      opt_deadline = (new Date).getTime() + this.Diff_Timeout * 1000;
  95
+    }
  96
+  }
  97
+  var deadline = opt_deadline;
  98
+
  99
+  // Check for null inputs.
  100
+  if (text1 == null || text2 == null) {
  101
+    throw new Error('Null input. (diff_main)');
  102
+  }
  103
+
  104
+  // Check for equality (speedup).
  105
+  if (text1 == text2) {
  106
+    if (text1) {
  107
+      return [[DIFF_EQUAL, text1]];
  108
+    }
  109
+    return [];
  110
+  }
  111
+
  112
+  if (typeof opt_checklines == 'undefined') {
  113
+    opt_checklines = true;
  114
+  }
  115
+  var checklines = opt_checklines;
  116
+
  117
+  // Trim off common prefix (speedup).
  118
+  var commonlength = this.diff_commonPrefix(text1, text2);
  119
+  var commonprefix = text1.substring(0, commonlength);
  120
+  text1 = text1.substring(commonlength);
  121
+  text2 = text2.substring(commonlength);
  122
+
  123
+  // Trim off common suffix (speedup).
  124
+  commonlength = this.diff_commonSuffix(text1, text2);
  125
+  var commonsuffix = text1.substring(text1.length - commonlength);
  126
+  text1 = text1.substring(0, text1.length - commonlength);
  127
+  text2 = text2.substring(0, text2.length - commonlength);
  128
+
  129
+  // Compute the diff on the middle block.
  130
+  var diffs = this.diff_compute_(text1, text2, checklines, deadline);
  131
+
  132
+  // Restore the prefix and suffix.
  133
+  if (commonprefix) {
  134
+    diffs.unshift([DIFF_EQUAL, commonprefix]);
  135
+  }
  136
+  if (commonsuffix) {
  137
+    diffs.push([DIFF_EQUAL, commonsuffix]);
  138
+  }
  139
+  this.diff_cleanupMerge(diffs);
  140
+  return diffs;
  141
+};
  142
+
  143
+
  144
+/**
  145
+ * Find the differences between two texts.  Assumes that the texts do not
  146
+ * have any common prefix or suffix.
  147
+ * @param {string} text1 Old string to be diffed.
  148
+ * @param {string} text2 New string to be diffed.
  149
+ * @param {boolean} checklines Speedup flag.  If false, then don't run a
  150
+ *     line-level diff first to identify the changed areas.
  151
+ *     If true, then run a faster, slightly less optimal diff.
  152
+ * @param {number} deadline Time when the diff should be complete by.
  153
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  154
+ * @private
  155
+ */
  156
+diff_match_patch.prototype.diff_compute_ = function(text1, text2, checklines,
  157
+    deadline) {
  158
+  var diffs;
  159
+
  160
+  if (!text1) {
  161
+    // Just add some text (speedup).
  162
+    return [[DIFF_INSERT, text2]];
  163
+  }
  164
+
  165
+  if (!text2) {
  166
+    // Just delete some text (speedup).
  167
+    return [[DIFF_DELETE, text1]];
  168
+  }
  169
+
  170
+  /** @type {?string} */
  171
+  var longtext = text1.length > text2.length ? text1 : text2;
  172
+  /** @type {?string} */
  173
+  var shorttext = text1.length > text2.length ? text2 : text1;
  174
+  var i = longtext.indexOf(shorttext);
  175
+  if (i != -1) {
  176
+    // Shorter text is inside the longer text (speedup).
  177
+    diffs = [[DIFF_INSERT, longtext.substring(0, i)],
  178
+             [DIFF_EQUAL, shorttext],
  179
+             [DIFF_INSERT, longtext.substring(i + shorttext.length)]];
  180
+    // Swap insertions for deletions if diff is reversed.
  181
+    if (text1.length > text2.length) {
  182
+      diffs[0][0] = diffs[2][0] = DIFF_DELETE;
  183
+    }
  184
+    return diffs;
  185
+  }
  186
+
  187
+  if (shorttext.length == 1) {
  188
+    // Single character string.
  189
+    // After the previous speedup, the character can't be an equality.
  190
+    return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
  191
+  }
  192
+  longtext = shorttext = null;  // Garbage collect.
  193
+
  194
+  // Check to see if the problem can be split in two.
  195
+  var hm = this.diff_halfMatch_(text1, text2);
  196
+  if (hm) {
  197
+    // A half-match was found, sort out the return data.
  198
+    var text1_a = hm[0];
  199
+    var text1_b = hm[1];
  200
+    var text2_a = hm[2];
  201
+    var text2_b = hm[3];
  202
+    var mid_common = hm[4];
  203
+    // Send both pairs off for separate processing.
  204
+    var diffs_a = this.diff_main(text1_a, text2_a, checklines, deadline);
  205
+    var diffs_b = this.diff_main(text1_b, text2_b, checklines, deadline);
  206
+    // Merge the results.
  207
+    return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b);
  208
+  }
  209
+
  210
+  if (checklines && text1.length > 100 && text2.length > 100) {
  211
+    return this.diff_lineMode_(text1, text2, deadline);
  212
+  }
  213
+
  214
+  return this.diff_bisect_(text1, text2, deadline);
  215
+};
  216
+
  217
+
  218
+/**
  219
+ * Do a quick line-level diff on both strings, then rediff the parts for
  220
+ * greater accuracy.
  221
+ * This speedup can produce non-minimal diffs.
  222
+ * @param {string} text1 Old string to be diffed.
  223
+ * @param {string} text2 New string to be diffed.
  224
+ * @param {number} deadline Time when the diff should be complete by.
  225
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  226
+ * @private
  227
+ */
  228
+diff_match_patch.prototype.diff_lineMode_ = function(text1, text2, deadline) {
  229
+  // Scan the text on a line-by-line basis first.
  230
+  var a = this.diff_linesToChars_(text1, text2);
  231
+  text1 = a.chars1;
  232
+  text2 = a.chars2;
  233
+  var linearray = a.lineArray;
  234
+
  235
+  var diffs = this.diff_main(text1, text2, false, deadline);
  236
+
  237
+  // Convert the diff back to original text.
  238
+  this.diff_charsToLines_(diffs, linearray);
  239
+  // Eliminate freak matches (e.g. blank lines)
  240
+  this.diff_cleanupSemantic(diffs);
  241
+
  242
+  // Rediff any replacement blocks, this time character-by-character.
  243
+  // Add a dummy entry at the end.
  244
+  diffs.push([DIFF_EQUAL, '']);
  245
+  var pointer = 0;
  246
+  var count_delete = 0;
  247
+  var count_insert = 0;
  248
+  var text_delete = '';
  249
+  var text_insert = '';
  250
+  while (pointer < diffs.length) {
  251
+    switch (diffs[pointer][0]) {
  252
+      case DIFF_INSERT:
  253
+        count_insert++;
  254
+        text_insert += diffs[pointer][1];
  255
+        break;
  256
+      case DIFF_DELETE:
  257
+        count_delete++;
  258
+        text_delete += diffs[pointer][1];
  259
+        break;
  260
+      case DIFF_EQUAL:
  261
+        // Upon reaching an equality, check for prior redundancies.
  262
+        if (count_delete >= 1 && count_insert >= 1) {
  263
+          // Delete the offending records and add the merged ones.
  264
+          diffs.splice(pointer - count_delete - count_insert,
  265
+                       count_delete + count_insert);
  266
+          pointer = pointer - count_delete - count_insert;
  267
+          var a = this.diff_main(text_delete, text_insert, false, deadline);
  268
+          for (var j = a.length - 1; j >= 0; j--) {
  269
+            diffs.splice(pointer, 0, a[j]);
  270
+          }
  271
+          pointer = pointer + a.length;
  272
+        }
  273
+        count_insert = 0;
  274
+        count_delete = 0;
  275
+        text_delete = '';
  276
+        text_insert = '';
  277
+        break;
  278
+    }
  279
+    pointer++;
  280
+  }
  281
+  diffs.pop();  // Remove the dummy entry at the end.
  282
+
  283
+  return diffs;
  284
+};
  285
+
  286
+
  287
+/**
  288
+ * Find the 'middle snake' of a diff, split the problem in two
  289
+ * and return the recursively constructed diff.
  290
+ * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
  291
+ * @param {string} text1 Old string to be diffed.
  292
+ * @param {string} text2 New string to be diffed.
  293
+ * @param {number} deadline Time at which to bail if not yet complete.
  294
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  295
+ * @private
  296
+ */
  297
+diff_match_patch.prototype.diff_bisect_ = function(text1, text2, deadline) {
  298
+  // Cache the text lengths to prevent multiple calls.
  299
+  var text1_length = text1.length;
  300
+  var text2_length = text2.length;
  301
+  var max_d = Math.ceil((text1_length + text2_length) / 2);
  302
+  var v_offset = max_d;
  303
+  var v_length = 2 * max_d;
  304
+  var v1 = new Array(v_length);
  305
+  var v2 = new Array(v_length);
  306
+  // Setting all elements to -1 is faster in Chrome & Firefox than mixing
  307
+  // integers and undefined.
  308
+  for (var x = 0; x < v_length; x++) {
  309
+    v1[x] = -1;
  310
+    v2[x] = -1;
  311
+  }
  312
+  v1[v_offset + 1] = 0;
  313
+  v2[v_offset + 1] = 0;
  314
+  var delta = text1_length - text2_length;
  315
+  // If the total number of characters is odd, then the front path will collide
  316
+  // with the reverse path.
  317
+  var front = (delta % 2 != 0);
  318
+  // Offsets for start and end of k loop.
  319
+  // Prevents mapping of space beyond the grid.
  320
+  var k1start = 0;
  321
+  var k1end = 0;
  322
+  var k2start = 0;
  323
+  var k2end = 0;
  324
+  for (var d = 0; d < max_d; d++) {
  325
+    // Bail out if deadline is reached.
  326
+    if ((new Date()).getTime() > deadline) {
  327
+      break;
  328
+    }
  329
+
  330
+    // Walk the front path one step.
  331
+    for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
  332
+      var k1_offset = v_offset + k1;
  333
+      var x1;
  334
+      if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) {
  335
+        x1 = v1[k1_offset + 1];
  336
+      } else {
  337
+        x1 = v1[k1_offset - 1] + 1;
  338
+      }
  339
+      var y1 = x1 - k1;
  340
+      while (x1 < text1_length && y1 < text2_length &&
  341
+             text1.charAt(x1) == text2.charAt(y1)) {
  342
+        x1++;
  343
+        y1++;
  344
+      }
  345
+      v1[k1_offset] = x1;
  346
+      if (x1 > text1_length) {
  347
+        // Ran off the right of the graph.
  348
+        k1end += 2;
  349
+      } else if (y1 > text2_length) {
  350
+        // Ran off the bottom of the graph.
  351
+        k1start += 2;
  352
+      } else if (front) {
  353
+        var k2_offset = v_offset + delta - k1;
  354
+        if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) {
  355
+          // Mirror x2 onto top-left coordinate system.
  356
+          var x2 = text1_length - v2[k2_offset];
  357
+          if (x1 >= x2) {
  358
+            // Overlap detected.
  359
+            return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);
  360
+          }
  361
+        }
  362
+      }
  363
+    }
  364
+
  365
+    // Walk the reverse path one step.
  366
+    for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
  367
+      var k2_offset = v_offset + k2;
  368
+      var x2;
  369
+      if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) {
  370
+        x2 = v2[k2_offset + 1];
  371
+      } else {
  372
+        x2 = v2[k2_offset - 1] + 1;
  373
+      }
  374
+      var y2 = x2 - k2;
  375
+      while (x2 < text1_length && y2 < text2_length &&
  376
+             text1.charAt(text1_length - x2 - 1) ==
  377
+             text2.charAt(text2_length - y2 - 1)) {
  378
+        x2++;
  379
+        y2++;
  380
+      }
  381
+      v2[k2_offset] = x2;
  382
+      if (x2 > text1_length) {
  383
+        // Ran off the left of the graph.
  384
+        k2end += 2;
  385
+      } else if (y2 > text2_length) {
  386
+        // Ran off the top of the graph.
  387
+        k2start += 2;
  388
+      } else if (!front) {
  389
+        var k1_offset = v_offset + delta - k2;
  390
+        if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) {
  391
+          var x1 = v1[k1_offset];
  392
+          var y1 = v_offset + x1 - k1_offset;
  393
+          // Mirror x2 onto top-left coordinate system.
  394
+          x2 = text1_length - x2;
  395
+          if (x1 >= x2) {
  396
+            // Overlap detected.
  397
+            return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);
  398
+          }
  399
+        }
  400
+      }
  401
+    }
  402
+  }
  403
+  // Diff took too long and hit the deadline or
  404
+  // number of diffs equals number of characters, no commonality at all.
  405
+  return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
  406
+};
  407
+
  408
+
  409
+/**
  410
+ * Given the location of the 'middle snake', split the diff in two parts
  411
+ * and recurse.
  412
+ * @param {string} text1 Old string to be diffed.
  413
+ * @param {string} text2 New string to be diffed.
  414
+ * @param {number} x Index of split point in text1.
  415
+ * @param {number} y Index of split point in text2.
  416
+ * @param {number} deadline Time at which to bail if not yet complete.
  417
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  418
+ * @private
  419
+ */
  420
+diff_match_patch.prototype.diff_bisectSplit_ = function(text1, text2, x, y,
  421
+    deadline) {
  422
+  var text1a = text1.substring(0, x);
  423
+  var text2a = text2.substring(0, y);
  424
+  var text1b = text1.substring(x);
  425
+  var text2b = text2.substring(y);
  426
+
  427
+  // Compute both diffs serially.
  428
+  var diffs = this.diff_main(text1a, text2a, false, deadline);
  429
+  var diffsb = this.diff_main(text1b, text2b, false, deadline);
  430
+
  431
+  return diffs.concat(diffsb);
  432
+};
  433
+
  434
+
  435
+/**
  436
+ * Split two texts into an array of strings.  Reduce the texts to a string of
  437
+ * hashes where each Unicode character represents one line.
  438
+ * @param {string} text1 First string.
  439
+ * @param {string} text2 Second string.
  440
+ * @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}
  441
+ *     An object containing the encoded text1, the encoded text2 and
  442
+ *     the array of unique strings.
  443
+ *     The zeroth element of the array of unique strings is intentionally blank.
  444
+ * @private
  445
+ */
  446
+diff_match_patch.prototype.diff_linesToChars_ = function(text1, text2) {
  447
+  var lineArray = [];  // e.g. lineArray[4] == 'Hello\n'
  448
+  var lineHash = {};   // e.g. lineHash['Hello\n'] == 4
  449
+
  450
+  // '\x00' is a valid character, but various debuggers don't like it.
  451
+  // So we'll insert a junk entry to avoid generating a null character.
  452
+  lineArray[0] = '';
  453
+
  454
+  /**
  455
+   * Split a text into an array of strings.  Reduce the texts to a string of
  456
+   * hashes where each Unicode character represents one line.
  457
+   * Modifies linearray and linehash through being a closure.
  458
+   * @param {string} text String to encode.
  459
+   * @return {string} Encoded string.
  460
+   * @private
  461
+   */
  462
+  function diff_linesToCharsMunge_(text) {
  463
+    var chars = '';
  464
+    // Walk the text, pulling out a substring for each line.
  465
+    // text.split('\n') would would temporarily double our memory footprint.
  466
+    // Modifying text would create many large strings to garbage collect.
  467
+    var lineStart = 0;
  468
+    var lineEnd = -1;
  469
+    // Keeping our own length variable is faster than looking it up.
  470
+    var lineArrayLength = lineArray.length;
  471
+    while (lineEnd < text.length - 1) {
  472
+      lineEnd = text.indexOf('\n', lineStart);
  473
+      if (lineEnd == -1) {
  474
+        lineEnd = text.length - 1;
  475
+      }
  476
+      var line = text.substring(lineStart, lineEnd + 1);
  477
+      lineStart = lineEnd + 1;
  478
+
  479
+      if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) :
  480
+          (lineHash[line] !== undefined)) {
  481
+        chars += String.fromCharCode(lineHash[line]);
  482
+      } else {
  483
+        chars += String.fromCharCode(lineArrayLength);
  484
+        lineHash[line] = lineArrayLength;
  485
+        lineArray[lineArrayLength++] = line;
  486
+      }
  487
+    }
  488
+    return chars;
  489
+  }
  490
+
  491
+  var chars1 = diff_linesToCharsMunge_(text1);
  492
+  var chars2 = diff_linesToCharsMunge_(text2);
  493
+  return {chars1: chars1, chars2: chars2, lineArray: lineArray};
  494
+};
  495
+
  496
+
  497
+/**
  498
+ * Rehydrate the text in a diff from a string of line hashes to real lines of
  499
+ * text.
  500
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  501
+ * @param {!Array.<string>} lineArray Array of unique strings.
  502
+ * @private
  503
+ */
  504
+diff_match_patch.prototype.diff_charsToLines_ = function(diffs, lineArray) {
  505
+  for (var x = 0; x < diffs.length; x++) {
  506
+    var chars = diffs[x][1];
  507
+    var text = [];
  508
+    for (var y = 0; y < chars.length; y++) {
  509
+      text[y] = lineArray[chars.charCodeAt(y)];
  510
+    }
  511
+    diffs[x][1] = text.join('');
  512
+  }
  513
+};
  514
+
  515
+
  516
+/**
  517
+ * Determine the common prefix of two strings.
  518
+ * @param {string} text1 First string.
  519
+ * @param {string} text2 Second string.
  520
+ * @return {number} The number of characters common to the start of each
  521
+ *     string.
  522
+ */
  523
+diff_match_patch.prototype.diff_commonPrefix = function(text1, text2) {
  524
+  // Quick check for common null cases.
  525
+  if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) {
  526
+    return 0;
  527
+  }
  528
+  // Binary search.
  529
+  // Performance analysis: http://neil.fraser.name/news/2007/10/09/
  530
+  var pointermin = 0;
  531
+  var pointermax = Math.min(text1.length, text2.length);
  532
+  var pointermid = pointermax;
  533
+  var pointerstart = 0;
  534
+  while (pointermin < pointermid) {
  535
+    if (text1.substring(pointerstart, pointermid) ==
  536
+        text2.substring(pointerstart, pointermid)) {
  537
+      pointermin = pointermid;
  538
+      pointerstart = pointermin;
  539
+    } else {
  540
+      pointermax = pointermid;
  541
+    }
  542
+    pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
  543
+  }
  544
+  return pointermid;
  545
+};
  546
+
  547
+
  548
+/**
  549
+ * Determine the common suffix of two strings.
  550
+ * @param {string} text1 First string.
  551
+ * @param {string} text2 Second string.
  552
+ * @return {number} The number of characters common to the end of each string.
  553
+ */
  554
+diff_match_patch.prototype.diff_commonSuffix = function(text1, text2) {
  555
+  // Quick check for common null cases.
  556
+  if (!text1 || !text2 ||
  557
+      text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) {
  558
+    return 0;
  559
+  }
  560
+  // Binary search.
  561
+  // Performance analysis: http://neil.fraser.name/news/2007/10/09/
  562
+  var pointermin = 0;
  563
+  var pointermax = Math.min(text1.length, text2.length);
  564
+  var pointermid = pointermax;
  565
+  var pointerend = 0;
  566
+  while (pointermin < pointermid) {
  567
+    if (text1.substring(text1.length - pointermid, text1.length - pointerend) ==
  568
+        text2.substring(text2.length - pointermid, text2.length - pointerend)) {
  569
+      pointermin = pointermid;
  570
+      pointerend = pointermin;
  571
+    } else {
  572
+      pointermax = pointermid;
  573
+    }
  574
+    pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
  575
+  }
  576
+  return pointermid;
  577
+};
  578
+
  579
+
  580
+/**
  581
+ * Determine if the suffix of one string is the prefix of another.
  582
+ * @param {string} text1 First string.
  583
+ * @param {string} text2 Second string.
  584
+ * @return {number} The number of characters common to the end of the first
  585
+ *     string and the start of the second string.
  586
+ * @private
  587
+ */
  588
+diff_match_patch.prototype.diff_commonOverlap_ = function(text1, text2) {
  589
+  // Cache the text lengths to prevent multiple calls.
  590
+  var text1_length = text1.length;
  591
+  var text2_length = text2.length;
  592
+  // Eliminate the null case.
  593
+  if (text1_length == 0 || text2_length == 0) {
  594
+    return 0;
  595
+  }
  596
+  // Truncate the longer string.
  597
+  if (text1_length > text2_length) {
  598
+    text1 = text1.substring(text1_length - text2_length);
  599
+  } else if (text1_length < text2_length) {
  600
+    text2 = text2.substring(0, text1_length);
  601
+  }
  602
+  var text_length = Math.min(text1_length, text2_length);
  603
+  // Quick check for the worst case.
  604
+  if (text1 == text2) {
  605
+    return text_length;
  606
+  }
  607
+
  608
+  // Start by looking for a single character match
  609
+  // and increase length until no match is found.
  610
+  // Performance analysis: http://neil.fraser.name/news/2010/11/04/
  611
+  var best = 0;
  612
+  var length = 1;
  613
+  while (true) {
  614
+    var pattern = text1.substring(text_length - length);
  615
+    var found = text2.indexOf(pattern);
  616
+    if (found == -1) {
  617
+      return best;
  618
+    }
  619
+    length += found;
  620
+    if (found == 0 || text1.substring(text_length - length) ==
  621
+        text2.substring(0, length)) {
  622
+      best = length;
  623
+      length++;
  624
+    }
  625
+  }
  626
+};
  627
+
  628
+
  629
+/**
  630
+ * Do the two texts share a substring which is at least half the length of the
  631
+ * longer text?
  632
+ * This speedup can produce non-minimal diffs.
  633
+ * @param {string} text1 First string.
  634
+ * @param {string} text2 Second string.
  635
+ * @return {Array.<string>} Five element Array, containing the prefix of
  636
+ *     text1, the suffix of text1, the prefix of text2, the suffix of
  637
+ *     text2 and the common middle.  Or null if there was no match.
  638
+ * @private
  639
+ */
  640
+diff_match_patch.prototype.diff_halfMatch_ = function(text1, text2) {
  641
+  if (this.Diff_Timeout <= 0) {
  642
+    // Don't risk returning a non-optimal diff if we have unlimited time.
  643
+    return null;
  644
+  }
  645
+  var longtext = text1.length > text2.length ? text1 : text2;
  646
+  var shorttext = text1.length > text2.length ? text2 : text1;
  647
+  if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
  648
+    return null;  // Pointless.
  649
+  }
  650
+  var dmp = this;  // 'this' becomes 'window' in a closure.
  651
+
  652
+  /**
  653
+   * Does a substring of shorttext exist within longtext such that the substring
  654
+   * is at least half the length of longtext?
  655
+   * Closure, but does not reference any external variables.
  656
+   * @param {string} longtext Longer string.
  657
+   * @param {string} shorttext Shorter string.
  658
+   * @param {number} i Start index of quarter length substring within longtext.
  659
+   * @return {Array.<string>} Five element Array, containing the prefix of
  660
+   *     longtext, the suffix of longtext, the prefix of shorttext, the suffix
  661
+   *     of shorttext and the common middle.  Or null if there was no match.
  662
+   * @private
  663
+   */
  664
+  function diff_halfMatchI_(longtext, shorttext, i) {
  665
+    // Start with a 1/4 length substring at position i as a seed.
  666
+    var seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
  667
+    var j = -1;
  668
+    var best_common = '';
  669
+    var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
  670
+    while ((j = shorttext.indexOf(seed, j + 1)) != -1) {
  671
+      var prefixLength = dmp.diff_commonPrefix(longtext.substring(i),
  672
+                                               shorttext.substring(j));
  673
+      var suffixLength = dmp.diff_commonSuffix(longtext.substring(0, i),
  674
+                                               shorttext.substring(0, j));
  675
+      if (best_common.length < suffixLength + prefixLength) {
  676
+        best_common = shorttext.substring(j - suffixLength, j) +
  677
+            shorttext.substring(j, j + prefixLength);
  678
+        best_longtext_a = longtext.substring(0, i - suffixLength);
  679
+        best_longtext_b = longtext.substring(i + prefixLength);
  680
+        best_shorttext_a = shorttext.substring(0, j - suffixLength);
  681
+        best_shorttext_b = shorttext.substring(j + prefixLength);
  682
+      }
  683
+    }
  684
+    if (best_common.length * 2 >= longtext.length) {
  685
+      return [best_longtext_a, best_longtext_b,
  686
+              best_shorttext_a, best_shorttext_b, best_common];
  687
+    } else {
  688
+      return null;
  689
+    }
  690
+  }
  691
+
  692
+  // First check if the second quarter is the seed for a half-match.
  693
+  var hm1 = diff_halfMatchI_(longtext, shorttext,
  694
+                             Math.ceil(longtext.length / 4));
  695
+  // Check again based on the third quarter.
  696
+  var hm2 = diff_halfMatchI_(longtext, shorttext,
  697
+                             Math.ceil(longtext.length / 2));
  698
+  var hm;
  699
+  if (!hm1 && !hm2) {
  700
+    return null;
  701
+  } else if (!hm2) {
  702
+    hm = hm1;
  703
+  } else if (!hm1) {
  704
+    hm = hm2;
  705
+  } else {
  706
+    // Both matched.  Select the longest.
  707
+    hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
  708
+  }
  709
+
  710
+  // A half-match was found, sort out the return data.
  711
+  var text1_a, text1_b, text2_a, text2_b;
  712
+  if (text1.length > text2.length) {
  713
+    text1_a = hm[0];
  714
+    text1_b = hm[1];
  715
+    text2_a = hm[2];
  716
+    text2_b = hm[3];
  717
+  } else {
  718
+    text2_a = hm[0];
  719
+    text2_b = hm[1];
  720
+    text1_a = hm[2];
  721
+    text1_b = hm[3];
  722
+  }
  723
+  var mid_common = hm[4];
  724
+  return [text1_a, text1_b, text2_a, text2_b, mid_common];
  725
+};
  726
+
  727
+
  728
+/**
  729
+ * Reduce the number of edits by eliminating semantically trivial equalities.
  730
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  731
+ */
  732
+diff_match_patch.prototype.diff_cleanupSemantic = function(diffs) {
  733
+  var changes = false;
  734
+  var equalities = [];  // Stack of indices where equalities are found.
  735
+  var equalitiesLength = 0;  // Keeping our own length var is faster in JS.
  736
+  /** @type {?string} */
  737
+  var lastequality = null;
  738
+  // Always equal to diffs[equalities[equalitiesLength - 1]][1]
  739
+  var pointer = 0;  // Index of current position.
  740
+  // Number of characters that changed prior to the equality.
  741
+  var length_insertions1 = 0;
  742
+  var length_deletions1 = 0;
  743
+  // Number of characters that changed after the equality.
  744
+  var length_insertions2 = 0;
  745
+  var length_deletions2 = 0;
  746
+  while (pointer < diffs.length) {
  747
+    if (diffs[pointer][0] == DIFF_EQUAL) {  // Equality found.
  748
+      equalities[equalitiesLength++] = pointer;
  749
+      length_insertions1 = length_insertions2;
  750
+      length_deletions1 = length_deletions2;
  751
+      length_insertions2 = 0;
  752
+      length_deletions2 = 0;
  753
+      lastequality = diffs[pointer][1];
  754
+    } else {  // An insertion or deletion.
  755
+      if (diffs[pointer][0] == DIFF_INSERT) {
  756
+        length_insertions2 += diffs[pointer][1].length;
  757
+      } else {
  758
+        length_deletions2 += diffs[pointer][1].length;
  759
+      }
  760
+      // Eliminate an equality that is smaller or equal to the edits on both
  761
+      // sides of it.
  762
+      if (lastequality && (lastequality.length <=
  763
+          Math.max(length_insertions1, length_deletions1)) &&
  764
+          (lastequality.length <= Math.max(length_insertions2,
  765
+                                           length_deletions2))) {
  766
+        // Duplicate record.
  767
+        diffs.splice(equalities[equalitiesLength - 1], 0,
  768
+                     [DIFF_DELETE, lastequality]);
  769
+        // Change second copy to insert.
  770
+        diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
  771
+        // Throw away the equality we just deleted.
  772
+        equalitiesLength--;
  773
+        // Throw away the previous equality (it needs to be reevaluated).
  774
+        equalitiesLength--;
  775
+        pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
  776
+        length_insertions1 = 0;  // Reset the counters.
  777
+        length_deletions1 = 0;
  778
+        length_insertions2 = 0;
  779
+        length_deletions2 = 0;
  780
+        lastequality = null;
  781
+        changes = true;
  782
+      }
  783
+    }
  784
+    pointer++;
  785
+  }
  786
+
  787
+  // Normalize the diff.
  788
+  if (changes) {
  789
+    this.diff_cleanupMerge(diffs);
  790
+  }
  791
+  this.diff_cleanupSemanticLossless(diffs);
  792
+
  793
+  // Find any overlaps between deletions and insertions.
  794
+  // e.g: <del>abcxxx</del><ins>xxxdef</ins>
  795
+  //   -> <del>abc</del>xxx<ins>def</ins>
  796
+  // e.g: <del>xxxabc</del><ins>defxxx</ins>
  797
+  //   -> <ins>def</ins>xxx<del>abc</del>
  798
+  // Only extract an overlap if it is as big as the edit ahead or behind it.
  799
+  pointer = 1;
  800
+  while (pointer < diffs.length) {
  801
+    if (diffs[pointer - 1][0] == DIFF_DELETE &&
  802
+        diffs[pointer][0] == DIFF_INSERT) {
  803
+      var deletion = diffs[pointer - 1][1];
  804
+      var insertion = diffs[pointer][1];
  805
+      var overlap_length1 = this.diff_commonOverlap_(deletion, insertion);
  806
+      var overlap_length2 = this.diff_commonOverlap_(insertion, deletion);
  807
+      if (overlap_length1 >= overlap_length2) {
  808
+        if (overlap_length1 >= deletion.length / 2 ||
  809
+            overlap_length1 >= insertion.length / 2) {
  810
+          // Overlap found.  Insert an equality and trim the surrounding edits.
  811
+          diffs.splice(pointer, 0,
  812
+              [DIFF_EQUAL, insertion.substring(0, overlap_length1)]);
  813
+          diffs[pointer - 1][1] =
  814
+              deletion.substring(0, deletion.length - overlap_length1);
  815
+          diffs[pointer + 1][1] = insertion.substring(overlap_length1);
  816
+          pointer++;
  817
+        }
  818
+      } else {
  819
+        if (overlap_length2 >= deletion.length / 2 ||
  820
+            overlap_length2 >= insertion.length / 2) {
  821
+          // Reverse overlap found.
  822
+          // Insert an equality and swap and trim the surrounding edits.
  823
+          diffs.splice(pointer, 0,
  824
+              [DIFF_EQUAL, deletion.substring(0, overlap_length2)]);
  825
+          diffs[pointer - 1][0] = DIFF_INSERT;
  826
+          diffs[pointer - 1][1] =
  827
+              insertion.substring(0, insertion.length - overlap_length2);
  828
+          diffs[pointer + 1][0] = DIFF_DELETE;
  829
+          diffs[pointer + 1][1] =
  830
+              deletion.substring(overlap_length2);
  831
+          pointer++;
  832
+        }
  833
+      }
  834
+      pointer++;
  835
+    }
  836
+    pointer++;
  837
+  }
  838
+};
  839
+
  840
+
  841
+/**
  842
+ * Look for single edits surrounded on both sides by equalities
  843
+ * which can be shifted sideways to align the edit to a word boundary.
  844
+ * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
  845
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  846
+ */
  847
+diff_match_patch.prototype.diff_cleanupSemanticLossless = function(diffs) {
  848
+  /**
  849
+   * Given two strings, compute a score representing whether the internal
  850
+   * boundary falls on logical boundaries.
  851
+   * Scores range from 6 (best) to 0 (worst).
  852
+   * Closure, but does not reference any external variables.
  853
+   * @param {string} one First string.
  854
+   * @param {string} two Second string.
  855
+   * @return {number} The score.
  856
+   * @private
  857
+   */
  858
+  function diff_cleanupSemanticScore_(one, two) {
  859
+    if (!one || !two) {
  860
+      // Edges are the best.
  861
+      return 6;
  862
+    }
  863
+
  864
+    // Each port of this function behaves slightly differently due to
  865
+    // subtle differences in each language's definition of things like
  866
+    // 'whitespace'.  Since this function's purpose is largely cosmetic,
  867
+    // the choice has been made to use each language's native features
  868
+    // rather than force total conformity.
  869
+    var char1 = one.charAt(one.length - 1);
  870
+    var char2 = two.charAt(0);
  871
+    var nonAlphaNumeric1 = char1.match(diff_match_patch.nonAlphaNumericRegex_);
  872
+    var nonAlphaNumeric2 = char2.match(diff_match_patch.nonAlphaNumericRegex_);
  873
+    var whitespace1 = nonAlphaNumeric1 &&
  874
+        char1.match(diff_match_patch.whitespaceRegex_);
  875
+    var whitespace2 = nonAlphaNumeric2 &&
  876
+        char2.match(diff_match_patch.whitespaceRegex_);
  877
+    var lineBreak1 = whitespace1 &&
  878
+        char1.match(diff_match_patch.linebreakRegex_);
  879
+    var lineBreak2 = whitespace2 &&
  880
+        char2.match(diff_match_patch.linebreakRegex_);
  881
+    var blankLine1 = lineBreak1 &&
  882
+        one.match(diff_match_patch.blanklineEndRegex_);
  883
+    var blankLine2 = lineBreak2 &&
  884
+        two.match(diff_match_patch.blanklineStartRegex_);
  885
+
  886
+    if (blankLine1 || blankLine2) {
  887
+      // Five points for blank lines.
  888
+      return 5;
  889
+    } else if (lineBreak1 || lineBreak2) {
  890
+      // Four points for line breaks.
  891
+      return 4;
  892
+    } else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) {
  893
+      // Three points for end of sentences.
  894
+      return 3;
  895
+    } else if (whitespace1 || whitespace2) {
  896
+      // Two points for whitespace.
  897
+      return 2;
  898
+    } else if (nonAlphaNumeric1 || nonAlphaNumeric2) {
  899
+      // One point for non-alphanumeric.
  900
+      return 1;
  901
+    }
  902
+    return 0;
  903
+  }
  904
+
  905
+  var pointer = 1;
  906
+  // Intentionally ignore the first and last element (don't need checking).
  907
+  while (pointer < diffs.length - 1) {
  908
+    if (diffs[pointer - 1][0] == DIFF_EQUAL &&
  909
+        diffs[pointer + 1][0] == DIFF_EQUAL) {
  910
+      // This is a single edit surrounded by equalities.
  911
+      var equality1 = diffs[pointer - 1][1];
  912
+      var edit = diffs[pointer][1];
  913
+      var equality2 = diffs[pointer + 1][1];
  914
+
  915
+      // First, shift the edit as far left as possible.
  916
+      var commonOffset = this.diff_commonSuffix(equality1, edit);
  917
+      if (commonOffset) {
  918
+        var commonString = edit.substring(edit.length - commonOffset);
  919
+        equality1 = equality1.substring(0, equality1.length - commonOffset);
  920
+        edit = commonString + edit.substring(0, edit.length - commonOffset);
  921
+        equality2 = commonString + equality2;
  922
+      }
  923
+
  924
+      // Second, step character by character right, looking for the best fit.
  925
+      var bestEquality1 = equality1;
  926
+      var bestEdit = edit;
  927
+      var bestEquality2 = equality2;
  928
+      var bestScore = diff_cleanupSemanticScore_(equality1, edit) +
  929
+          diff_cleanupSemanticScore_(edit, equality2);
  930
+      while (edit.charAt(0) === equality2.charAt(0)) {
  931
+        equality1 += edit.charAt(0);
  932
+        edit = edit.substring(1) + equality2.charAt(0);
  933
+        equality2 = equality2.substring(1);
  934
+        var score = diff_cleanupSemanticScore_(equality1, edit) +
  935
+            diff_cleanupSemanticScore_(edit, equality2);
  936
+        // The >= encourages trailing rather than leading whitespace on edits.
  937
+        if (score >= bestScore) {
  938
+          bestScore = score;
  939
+          bestEquality1 = equality1;
  940
+          bestEdit = edit;
  941
+          bestEquality2 = equality2;
  942
+        }
  943
+      }
  944
+
  945
+      if (diffs[pointer - 1][1] != bestEquality1) {
  946
+        // We have an improvement, save it back to the diff.
  947
+        if (bestEquality1) {
  948
+          diffs[pointer - 1][1] = bestEquality1;
  949
+        } else {
  950
+          diffs.splice(pointer - 1, 1);
  951
+          pointer--;
  952
+        }
  953
+        diffs[pointer][1] = bestEdit;
  954
+        if (bestEquality2) {
  955
+          diffs[pointer + 1][1] = bestEquality2;
  956
+        } else {
  957
+          diffs.splice(pointer + 1, 1);
  958
+          pointer--;
  959
+        }
  960
+      }
  961
+    }
  962
+    pointer++;
  963
+  }
  964
+};
  965
+
  966
+// Define some regex patterns for matching boundaries.
  967
+diff_match_patch.nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/;
  968
+diff_match_patch.whitespaceRegex_ = /\s/;
  969
+diff_match_patch.linebreakRegex_ = /[\r\n]/;
  970
+diff_match_patch.blanklineEndRegex_ = /\n\r?\n$/;
  971
+diff_match_patch.blanklineStartRegex_ = /^\r?\n\r?\n/;
  972
+
  973
+/**
  974
+ * Reduce the number of edits by eliminating operationally trivial equalities.
  975
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  976
+ */
  977
+diff_match_patch.prototype.diff_cleanupEfficiency = function(diffs) {
  978
+  var changes = false;
  979
+  var equalities = [];  // Stack of indices where equalities are found.
  980
+  var equalitiesLength = 0;  // Keeping our own length var is faster in JS.
  981
+  /** @type {?string} */
  982
+  var lastequality = null;
  983
+  // Always equal to diffs[equalities[equalitiesLength - 1]][1]
  984
+  var pointer = 0;  // Index of current position.
  985
+  // Is there an insertion operation before the last equality.
  986
+  var pre_ins = false;
  987
+  // Is there a deletion operation before the last equality.
  988
+  var pre_del = false;
  989
+  // Is there an insertion operation after the last equality.
  990
+  var post_ins = false;
  991
+  // Is there a deletion operation after the last equality.
  992
+  var post_del = false;
  993
+  while (pointer < diffs.length) {
  994
+    if (diffs[pointer][0] == DIFF_EQUAL) {  // Equality found.
  995
+      if (diffs[pointer][1].length < this.Diff_EditCost &&
  996
+          (post_ins || post_del)) {
  997
+        // Candidate found.
  998
+        equalities[equalitiesLength++] = pointer;
  999
+        pre_ins = post_ins;
  1000
+        pre_del = post_del;
  1001
+        lastequality = diffs[pointer][1];
  1002
+      } else {
  1003
+        // Not a candidate, and can never become one.
  1004
+        equalitiesLength = 0;
  1005
+        lastequality = null;
  1006
+      }
  1007
+      post_ins = post_del = false;
  1008
+    } else {  // An insertion or deletion.
  1009
+      if (diffs[pointer][0] == DIFF_DELETE) {
  1010
+        post_del = true;
  1011
+      } else {
  1012
+        post_ins = true;
  1013
+      }
  1014
+      /*
  1015
+       * Five types to be split:
  1016
+       * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
  1017
+       * <ins>A</ins>X<ins>C</ins><del>D</del>
  1018
+       * <ins>A</ins><del>B</del>X<ins>C</ins>
  1019
+       * <ins>A</del>X<ins>C</ins><del>D</del>
  1020
+       * <ins>A</ins><del>B</del>X<del>C</del>
  1021
+       */
  1022
+      if (lastequality && ((pre_ins && pre_del && post_ins && post_del) ||
  1023
+                           ((lastequality.length < this.Diff_EditCost / 2) &&
  1024
+                            (pre_ins + pre_del + post_ins + post_del) == 3))) {
  1025
+        // Duplicate record.
  1026
+        diffs.splice(equalities[equalitiesLength - 1], 0,
  1027
+                     [DIFF_DELETE, lastequality]);
  1028
+        // Change second copy to insert.
  1029
+        diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
  1030
+        equalitiesLength--;  // Throw away the equality we just deleted;
  1031
+        lastequality = null;
  1032
+        if (pre_ins && pre_del) {
  1033
+          // No changes made which could affect previous entry, keep going.
  1034
+          post_ins = post_del = true;
  1035
+          equalitiesLength = 0;
  1036
+        } else {
  1037
+          equalitiesLength--;  // Throw away the previous equality.
  1038
+          pointer = equalitiesLength > 0 ?
  1039
+              equalities[equalitiesLength - 1] : -1;
  1040
+          post_ins = post_del = false;
  1041
+        }
  1042
+        changes = true;
  1043
+      }
  1044
+    }
  1045
+    pointer++;
  1046
+  }
  1047
+
  1048
+  if (changes) {
  1049
+    this.diff_cleanupMerge(diffs);
  1050
+  }
  1051
+};
  1052
+
  1053
+
  1054
+/**
  1055
+ * Reorder and merge like edit sections.  Merge equalities.
  1056
+ * Any edit section can move as long as it doesn't cross an equality.
  1057
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  1058
+ */
  1059
+diff_match_patch.prototype.diff_cleanupMerge = function(diffs) {
  1060
+  diffs.push([DIFF_EQUAL, '']);  // Add a dummy entry at the end.
  1061
+  var pointer = 0;
  1062
+  var count_delete = 0;
  1063
+  var count_insert = 0;
  1064
+  var text_delete = '';
  1065
+  var text_insert = '';
  1066
+  var commonlength;
  1067
+  while (pointer < diffs.length) {
  1068
+    switch (diffs[pointer][0]) {
  1069
+      case DIFF_INSERT:
  1070
+        count_insert++;
  1071
+        text_insert += diffs[pointer][1];
  1072
+        pointer++;
  1073
+        break;
  1074
+      case DIFF_DELETE:
  1075
+        count_delete++;
  1076
+        text_delete += diffs[pointer][1];
  1077
+        pointer++;
  1078
+        break;
  1079
+      case DIFF_EQUAL:
  1080
+        // Upon reaching an equality