Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/util/dmp.js
Views: 687
/*1* This file is part of CoCalc: However, the license is Apache V2, exactly as2* for the original upstream code. We have barely changed it. -- William Stein3*/45/**6* Diff Match and Patch7* Copyright 2018 The diff-match-patch Authors.8* https://github.com/google/diff-match-patch9*10* Licensed under the Apache License, Version 2.0 (the "License");11* you may not use this file except in compliance with the License.12* You may obtain a copy of the License at13*14* http://www.apache.org/licenses/LICENSE-2.015*16* Unless required by applicable law or agreed to in writing, software17* distributed under the License is distributed on an "AS IS" BASIS,18* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.19* See the License for the specific language governing permissions and20* limitations under the License.21*/2223/**24* @fileoverview Computes the difference between two texts to create a patch.25* Applies the patch onto another text, allowing for errors.26* @author [email protected] (Neil Fraser)27*/2829/**30* Class containing the diff, match and patch methods.31* @constructor32*/3334export const diff_match_patch = function () {35// Defaults.36// Redefine these in your program to override the defaults.3738// Number of seconds to map a diff before giving up (0 for infinity).39this.Diff_Timeout = 1.0;40// Cost of an empty edit operation in terms of edit characters.41this.Diff_EditCost = 4;42// At what point is no match declared (0.0 = perfection, 1.0 = very loose).43this.Match_Threshold = 0.5;44// How far to search for a match (0 = exact location, 1000+ = broad match).45// A match this many characters away from the expected location will add46// 1.0 to the score (0.0 is a perfect match).47this.Match_Distance = 1000;48// When deleting a large block of text (over ~64 characters), how close do49// the contents have to be to match the expected contents. (0.0 = perfection,50// 1.0 = very loose). Note that Match_Threshold controls how closely the51// end points of a delete need to match.52this.Patch_DeleteThreshold = 0.5;53// Chunk size for context length.54this.Patch_Margin = 4;5556// The number of bits in an int.57this.Match_MaxBits = 32;58};5960// DIFF FUNCTIONS6162/**63* The data structure representing a diff is an array of tuples:64* [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]65* which means: delete 'Hello', add 'Goodbye' and keep ' world.'66*/67export const DIFF_DELETE = -1;68export const DIFF_INSERT = 1;69export const DIFF_EQUAL = 0;7071/**72* Class representing one diff tuple.73* Attempts to look like a two-element array (which is what this used to be).74* @param {number} op Operation, one of: DIFF_DELETE, DIFF_INSERT, DIFF_EQUAL.75* @param {string} text Text to be deleted, inserted, or retained.76* @constructor77*/78diff_match_patch.Diff = function (op, text) {79this[0] = op;80this[1] = text;81};8283diff_match_patch.Diff.prototype.length = 2;8485/**86* Emulate the output of a two-element array.87* @return {string} Diff operation as a string.88*/89diff_match_patch.Diff.prototype.toString = function () {90return this[0] + "," + this[1];91};9293/**94* Find the differences between two texts. Simplifies the problem by stripping95* any common prefix or suffix off the texts before diffing.96* @param {string} text1 Old string to be diffed.97* @param {string} text2 New string to be diffed.98* @param {boolean=} opt_checklines Optional speedup flag. If present and false,99* then don't run a line-level diff first to identify the changed areas.100* Defaults to true, which does a faster, slightly less optimal diff.101* @param {number=} opt_deadline Optional time when the diff should be complete102* by. Used internally for recursive calls. Users should set DiffTimeout103* instead.104* @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.105*/106diff_match_patch.prototype.diff_main = function (107text1,108text2,109opt_checklines,110opt_deadline,111) {112// Set a deadline by which time the diff must be complete.113if (typeof opt_deadline == "undefined") {114if (this.Diff_Timeout <= 0) {115opt_deadline = Number.MAX_VALUE;116} else {117opt_deadline = new Date().getTime() + this.Diff_Timeout * 1000;118}119}120var deadline = opt_deadline;121122// Check for null inputs.123if (text1 == null || text2 == null) {124throw new Error("Null input. (diff_main)");125}126127// Check for equality (speedup).128if (text1 == text2) {129if (text1) {130return [new diff_match_patch.Diff(DIFF_EQUAL, text1)];131}132return [];133}134135if (typeof opt_checklines == "undefined") {136opt_checklines = true;137}138var checklines = opt_checklines;139140// Trim off common prefix (speedup).141var commonlength = this.diff_commonPrefix(text1, text2);142var commonprefix = text1.substring(0, commonlength);143text1 = text1.substring(commonlength);144text2 = text2.substring(commonlength);145146// Trim off common suffix (speedup).147commonlength = this.diff_commonSuffix(text1, text2);148var commonsuffix = text1.substring(text1.length - commonlength);149text1 = text1.substring(0, text1.length - commonlength);150text2 = text2.substring(0, text2.length - commonlength);151152// Compute the diff on the middle block.153var diffs = this.diff_compute_(text1, text2, checklines, deadline);154155// Restore the prefix and suffix.156if (commonprefix) {157diffs.unshift(new diff_match_patch.Diff(DIFF_EQUAL, commonprefix));158}159if (commonsuffix) {160diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, commonsuffix));161}162this.diff_cleanupMerge(diffs);163return diffs;164};165166/**167* Find the differences between two texts. Assumes that the texts do not168* have any common prefix or suffix.169* @param {string} text1 Old string to be diffed.170* @param {string} text2 New string to be diffed.171* @param {boolean} checklines Speedup flag. If false, then don't run a172* line-level diff first to identify the changed areas.173* If true, then run a faster, slightly less optimal diff.174* @param {number} deadline Time when the diff should be complete by.175* @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.176* @private177*/178diff_match_patch.prototype.diff_compute_ = function (179text1,180text2,181checklines,182deadline,183) {184var diffs;185186if (!text1) {187// Just add some text (speedup).188return [new diff_match_patch.Diff(DIFF_INSERT, text2)];189}190191if (!text2) {192// Just delete some text (speedup).193return [new diff_match_patch.Diff(DIFF_DELETE, text1)];194}195196var longtext = text1.length > text2.length ? text1 : text2;197var shorttext = text1.length > text2.length ? text2 : text1;198var i = longtext.indexOf(shorttext);199if (i != -1) {200// Shorter text is inside the longer text (speedup).201diffs = [202new diff_match_patch.Diff(DIFF_INSERT, longtext.substring(0, i)),203new diff_match_patch.Diff(DIFF_EQUAL, shorttext),204new diff_match_patch.Diff(205DIFF_INSERT,206longtext.substring(i + shorttext.length),207),208];209// Swap insertions for deletions if diff is reversed.210if (text1.length > text2.length) {211diffs[0][0] = diffs[2][0] = DIFF_DELETE;212}213return diffs;214}215216if (shorttext.length == 1) {217// Single character string.218// After the previous speedup, the character can't be an equality.219return [220new diff_match_patch.Diff(DIFF_DELETE, text1),221new diff_match_patch.Diff(DIFF_INSERT, text2),222];223}224225// Check to see if the problem can be split in two.226var hm = this.diff_halfMatch_(text1, text2);227if (hm) {228// A half-match was found, sort out the return data.229var text1_a = hm[0];230var text1_b = hm[1];231var text2_a = hm[2];232var text2_b = hm[3];233var mid_common = hm[4];234// Send both pairs off for separate processing.235var diffs_a = this.diff_main(text1_a, text2_a, checklines, deadline);236var diffs_b = this.diff_main(text1_b, text2_b, checklines, deadline);237// Merge the results.238return diffs_a.concat(239[new diff_match_patch.Diff(DIFF_EQUAL, mid_common)],240diffs_b,241);242}243244if (checklines && text1.length > 100 && text2.length > 100) {245return this.diff_lineMode_(text1, text2, deadline);246}247248return this.diff_bisect_(text1, text2, deadline);249};250251/**252* Do a quick line-level diff on both strings, then rediff the parts for253* greater accuracy.254* This speedup can produce non-minimal diffs.255* @param {string} text1 Old string to be diffed.256* @param {string} text2 New string to be diffed.257* @param {number} deadline Time when the diff should be complete by.258* @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.259* @private260*/261diff_match_patch.prototype.diff_lineMode_ = function (text1, text2, deadline) {262// Scan the text on a line-by-line basis first.263var a = this.diff_linesToChars_(text1, text2);264text1 = a.chars1;265text2 = a.chars2;266var linearray = a.lineArray;267268var diffs = this.diff_main(text1, text2, false, deadline);269270// Convert the diff back to original text.271this.diff_charsToLines_(diffs, linearray);272// Eliminate freak matches (e.g. blank lines)273this.diff_cleanupSemantic(diffs);274275// Rediff any replacement blocks, this time character-by-character.276// Add a dummy entry at the end.277diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, ""));278var pointer = 0;279var count_delete = 0;280var count_insert = 0;281var text_delete = "";282var text_insert = "";283while (pointer < diffs.length) {284switch (diffs[pointer][0]) {285case DIFF_INSERT:286count_insert++;287text_insert += diffs[pointer][1];288break;289case DIFF_DELETE:290count_delete++;291text_delete += diffs[pointer][1];292break;293case DIFF_EQUAL:294// Upon reaching an equality, check for prior redundancies.295if (count_delete >= 1 && count_insert >= 1) {296// Delete the offending records and add the merged ones.297diffs.splice(298pointer - count_delete - count_insert,299count_delete + count_insert,300);301pointer = pointer - count_delete - count_insert;302var subDiff = this.diff_main(303text_delete,304text_insert,305false,306deadline,307);308for (var j = subDiff.length - 1; j >= 0; j--) {309diffs.splice(pointer, 0, subDiff[j]);310}311pointer = pointer + subDiff.length;312}313count_insert = 0;314count_delete = 0;315text_delete = "";316text_insert = "";317break;318}319pointer++;320}321diffs.pop(); // Remove the dummy entry at the end.322323return diffs;324};325326/**327* Find the 'middle snake' of a diff, split the problem in two328* and return the recursively constructed diff.329* See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.330* @param {string} text1 Old string to be diffed.331* @param {string} text2 New string to be diffed.332* @param {number} deadline Time at which to bail if not yet complete.333* @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.334* @private335*/336diff_match_patch.prototype.diff_bisect_ = function (text1, text2, deadline) {337// Cache the text lengths to prevent multiple calls.338var text1_length = text1.length;339var text2_length = text2.length;340var max_d = Math.ceil((text1_length + text2_length) / 2);341var v_offset = max_d;342var v_length = 2 * max_d;343var v1 = new Array(v_length);344var v2 = new Array(v_length);345// Setting all elements to -1 is faster in Chrome & Firefox than mixing346// integers and undefined.347for (var x = 0; x < v_length; x++) {348v1[x] = -1;349v2[x] = -1;350}351v1[v_offset + 1] = 0;352v2[v_offset + 1] = 0;353var delta = text1_length - text2_length;354// If the total number of characters is odd, then the front path will collide355// with the reverse path.356var front = delta % 2 != 0;357// Offsets for start and end of k loop.358// Prevents mapping of space beyond the grid.359var k1start = 0;360var k1end = 0;361var k2start = 0;362var k2end = 0;363for (var d = 0; d < max_d; d++) {364// Bail out if deadline is reached.365if (new Date().getTime() > deadline) {366break;367}368369// Walk the front path one step.370for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {371var k1_offset = v_offset + k1;372var x1;373if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) {374x1 = v1[k1_offset + 1];375} else {376x1 = v1[k1_offset - 1] + 1;377}378var y1 = x1 - k1;379while (380x1 < text1_length &&381y1 < text2_length &&382text1.charAt(x1) == text2.charAt(y1)383) {384x1++;385y1++;386}387v1[k1_offset] = x1;388if (x1 > text1_length) {389// Ran off the right of the graph.390k1end += 2;391} else if (y1 > text2_length) {392// Ran off the bottom of the graph.393k1start += 2;394} else if (front) {395var k2_offset = v_offset + delta - k1;396if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) {397// Mirror x2 onto top-left coordinate system.398var x2 = text1_length - v2[k2_offset];399if (x1 >= x2) {400// Overlap detected.401return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);402}403}404}405}406407// Walk the reverse path one step.408for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {409var k2_offset = v_offset + k2;410var x2;411if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) {412x2 = v2[k2_offset + 1];413} else {414x2 = v2[k2_offset - 1] + 1;415}416var y2 = x2 - k2;417while (418x2 < text1_length &&419y2 < text2_length &&420text1.charAt(text1_length - x2 - 1) ==421text2.charAt(text2_length - y2 - 1)422) {423x2++;424y2++;425}426v2[k2_offset] = x2;427if (x2 > text1_length) {428// Ran off the left of the graph.429k2end += 2;430} else if (y2 > text2_length) {431// Ran off the top of the graph.432k2start += 2;433} else if (!front) {434var k1_offset = v_offset + delta - k2;435if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) {436var x1 = v1[k1_offset];437var y1 = v_offset + x1 - k1_offset;438// Mirror x2 onto top-left coordinate system.439x2 = text1_length - x2;440if (x1 >= x2) {441// Overlap detected.442return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);443}444}445}446}447}448// Diff took too long and hit the deadline or449// number of diffs equals number of characters, no commonality at all.450return [451new diff_match_patch.Diff(DIFF_DELETE, text1),452new diff_match_patch.Diff(DIFF_INSERT, text2),453];454};455456/**457* Given the location of the 'middle snake', split the diff in two parts458* and recurse.459* @param {string} text1 Old string to be diffed.460* @param {string} text2 New string to be diffed.461* @param {number} x Index of split point in text1.462* @param {number} y Index of split point in text2.463* @param {number} deadline Time at which to bail if not yet complete.464* @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.465* @private466*/467diff_match_patch.prototype.diff_bisectSplit_ = function (468text1,469text2,470x,471y,472deadline,473) {474var text1a = text1.substring(0, x);475var text2a = text2.substring(0, y);476var text1b = text1.substring(x);477var text2b = text2.substring(y);478479// Compute both diffs serially.480var diffs = this.diff_main(text1a, text2a, false, deadline);481var diffsb = this.diff_main(text1b, text2b, false, deadline);482483return diffs.concat(diffsb);484};485486/**487* Split two texts into an array of strings. Reduce the texts to a string of488* hashes where each Unicode character represents one line.489* @param {string} text1 First string.490* @param {string} text2 Second string.491* @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}492* An object containing the encoded text1, the encoded text2 and493* the array of unique strings.494* The zeroth element of the array of unique strings is intentionally blank.495* @private496*/497diff_match_patch.prototype.diff_linesToChars_ = function (text1, text2) {498var lineArray = []; // e.g. lineArray[4] == 'Hello\n'499var lineHash = {}; // e.g. lineHash['Hello\n'] == 4500501// '\x00' is a valid character, but various debuggers don't like it.502// So we'll insert a junk entry to avoid generating a null character.503lineArray[0] = "";504505/**506* Split a text into an array of strings. Reduce the texts to a string of507* hashes where each Unicode character represents one line.508* Modifies linearray and linehash through being a closure.509* @param {string} text String to encode.510* @return {string} Encoded string.511* @private512*/513function diff_linesToCharsMunge_(text) {514var chars = "";515// Walk the text, pulling out a substring for each line.516// text.split('\n') would would temporarily double our memory footprint.517// Modifying text would create many large strings to garbage collect.518var lineStart = 0;519var lineEnd = -1;520// Keeping our own length variable is faster than looking it up.521var lineArrayLength = lineArray.length;522while (lineEnd < text.length - 1) {523lineEnd = text.indexOf("\n", lineStart);524if (lineEnd == -1) {525lineEnd = text.length - 1;526}527var line = text.substring(lineStart, lineEnd + 1);528529if (530lineHash.hasOwnProperty531? lineHash.hasOwnProperty(line)532: lineHash[line] !== undefined533) {534chars += String.fromCharCode(lineHash[line]);535} else {536if (lineArrayLength == maxLines) {537// Bail out at 65535 because538// String.fromCharCode(65536) == String.fromCharCode(0)539line = text.substring(lineStart);540lineEnd = text.length;541}542chars += String.fromCharCode(lineArrayLength);543lineHash[line] = lineArrayLength;544lineArray[lineArrayLength++] = line;545}546lineStart = lineEnd + 1;547}548return chars;549}550// Allocate 2/3rds of the space for text1, the rest for text2.551var maxLines = 40000;552var chars1 = diff_linesToCharsMunge_(text1);553maxLines = 65535;554var chars2 = diff_linesToCharsMunge_(text2);555return { chars1: chars1, chars2: chars2, lineArray: lineArray };556};557558/**559* Rehydrate the text in a diff from a string of line hashes to real lines of560* text.561* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.562* @param {!Array.<string>} lineArray Array of unique strings.563* @private564*/565diff_match_patch.prototype.diff_charsToLines_ = function (diffs, lineArray) {566for (var i = 0; i < diffs.length; i++) {567var chars = diffs[i][1];568var text = [];569for (var j = 0; j < chars.length; j++) {570text[j] = lineArray[chars.charCodeAt(j)];571}572diffs[i][1] = text.join("");573}574};575576/**577* Determine the common prefix of two strings.578* @param {string} text1 First string.579* @param {string} text2 Second string.580* @return {number} The number of characters common to the start of each581* string.582*/583diff_match_patch.prototype.diff_commonPrefix = function (text1, text2) {584// Quick check for common null cases.585if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) {586return 0;587}588// Binary search.589// Performance analysis: https://neil.fraser.name/news/2007/10/09/590var pointermin = 0;591var pointermax = Math.min(text1.length, text2.length);592var pointermid = pointermax;593var pointerstart = 0;594while (pointermin < pointermid) {595if (596text1.substring(pointerstart, pointermid) ==597text2.substring(pointerstart, pointermid)598) {599pointermin = pointermid;600pointerstart = pointermin;601} else {602pointermax = pointermid;603}604pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);605}606return pointermid;607};608609/**610* Determine the common suffix of two strings.611* @param {string} text1 First string.612* @param {string} text2 Second string.613* @return {number} The number of characters common to the end of each string.614*/615diff_match_patch.prototype.diff_commonSuffix = function (text1, text2) {616// Quick check for common null cases.617if (618!text1 ||619!text2 ||620text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)621) {622return 0;623}624// Binary search.625// Performance analysis: https://neil.fraser.name/news/2007/10/09/626var pointermin = 0;627var pointermax = Math.min(text1.length, text2.length);628var pointermid = pointermax;629var pointerend = 0;630while (pointermin < pointermid) {631if (632text1.substring(text1.length - pointermid, text1.length - pointerend) ==633text2.substring(text2.length - pointermid, text2.length - pointerend)634) {635pointermin = pointermid;636pointerend = pointermin;637} else {638pointermax = pointermid;639}640pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);641}642return pointermid;643};644645/**646* Determine if the suffix of one string is the prefix of another.647* @param {string} text1 First string.648* @param {string} text2 Second string.649* @return {number} The number of characters common to the end of the first650* string and the start of the second string.651* @private652*/653diff_match_patch.prototype.diff_commonOverlap_ = function (text1, text2) {654// Cache the text lengths to prevent multiple calls.655var text1_length = text1.length;656var text2_length = text2.length;657// Eliminate the null case.658if (text1_length == 0 || text2_length == 0) {659return 0;660}661// Truncate the longer string.662if (text1_length > text2_length) {663text1 = text1.substring(text1_length - text2_length);664} else if (text1_length < text2_length) {665text2 = text2.substring(0, text1_length);666}667var text_length = Math.min(text1_length, text2_length);668// Quick check for the worst case.669if (text1 == text2) {670return text_length;671}672673// Start by looking for a single character match674// and increase length until no match is found.675// Performance analysis: https://neil.fraser.name/news/2010/11/04/676var best = 0;677var length = 1;678while (true) {679var pattern = text1.substring(text_length - length);680var found = text2.indexOf(pattern);681if (found == -1) {682return best;683}684length += found;685if (686found == 0 ||687text1.substring(text_length - length) == text2.substring(0, length)688) {689best = length;690length++;691}692}693};694695/**696* Do the two texts share a substring which is at least half the length of the697* longer text?698* This speedup can produce non-minimal diffs.699* @param {string} text1 First string.700* @param {string} text2 Second string.701* @return {Array.<string>} Five element Array, containing the prefix of702* text1, the suffix of text1, the prefix of text2, the suffix of703* text2 and the common middle. Or null if there was no match.704* @private705*/706diff_match_patch.prototype.diff_halfMatch_ = function (text1, text2) {707if (this.Diff_Timeout <= 0) {708// Don't risk returning a non-optimal diff if we have unlimited time.709return null;710}711var longtext = text1.length > text2.length ? text1 : text2;712var shorttext = text1.length > text2.length ? text2 : text1;713if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {714return null; // Pointless.715}716var dmp = this; // 'this' becomes 'window' in a closure.717718/**719* Does a substring of shorttext exist within longtext such that the substring720* is at least half the length of longtext?721* Closure, but does not reference any external variables.722* @param {string} longtext Longer string.723* @param {string} shorttext Shorter string.724* @param {number} i Start index of quarter length substring within longtext.725* @return {Array.<string>} Five element Array, containing the prefix of726* longtext, the suffix of longtext, the prefix of shorttext, the suffix727* of shorttext and the common middle. Or null if there was no match.728* @private729*/730function diff_halfMatchI_(longtext, shorttext, i) {731// Start with a 1/4 length substring at position i as a seed.732var seed = longtext.substring(i, i + Math.floor(longtext.length / 4));733var j = -1;734var best_common = "";735var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;736while ((j = shorttext.indexOf(seed, j + 1)) != -1) {737var prefixLength = dmp.diff_commonPrefix(738longtext.substring(i),739shorttext.substring(j),740);741var suffixLength = dmp.diff_commonSuffix(742longtext.substring(0, i),743shorttext.substring(0, j),744);745if (best_common.length < suffixLength + prefixLength) {746best_common =747shorttext.substring(j - suffixLength, j) +748shorttext.substring(j, j + prefixLength);749best_longtext_a = longtext.substring(0, i - suffixLength);750best_longtext_b = longtext.substring(i + prefixLength);751best_shorttext_a = shorttext.substring(0, j - suffixLength);752best_shorttext_b = shorttext.substring(j + prefixLength);753}754}755if (best_common.length * 2 >= longtext.length) {756return [757best_longtext_a,758best_longtext_b,759best_shorttext_a,760best_shorttext_b,761best_common,762];763} else {764return null;765}766}767768// First check if the second quarter is the seed for a half-match.769var hm1 = diff_halfMatchI_(770longtext,771shorttext,772Math.ceil(longtext.length / 4),773);774// Check again based on the third quarter.775var hm2 = diff_halfMatchI_(776longtext,777shorttext,778Math.ceil(longtext.length / 2),779);780var hm;781if (!hm1 && !hm2) {782return null;783} else if (!hm2) {784hm = hm1;785} else if (!hm1) {786hm = hm2;787} else {788// Both matched. Select the longest.789hm = hm1[4].length > hm2[4].length ? hm1 : hm2;790}791792// A half-match was found, sort out the return data.793var text1_a, text1_b, text2_a, text2_b;794if (text1.length > text2.length) {795text1_a = hm[0];796text1_b = hm[1];797text2_a = hm[2];798text2_b = hm[3];799} else {800text2_a = hm[0];801text2_b = hm[1];802text1_a = hm[2];803text1_b = hm[3];804}805var mid_common = hm[4];806return [text1_a, text1_b, text2_a, text2_b, mid_common];807};808809/**810* Reduce the number of edits by eliminating semantically trivial equalities.811* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.812*/813diff_match_patch.prototype.diff_cleanupSemantic = function (diffs) {814var changes = false;815var equalities = []; // Stack of indices where equalities are found.816var equalitiesLength = 0; // Keeping our own length var is faster in JS.817/** @type {?string} */818var lastEquality = null;819// Always equal to diffs[equalities[equalitiesLength - 1]][1]820var pointer = 0; // Index of current position.821// Number of characters that changed prior to the equality.822var length_insertions1 = 0;823var length_deletions1 = 0;824// Number of characters that changed after the equality.825var length_insertions2 = 0;826var length_deletions2 = 0;827while (pointer < diffs.length) {828if (diffs[pointer][0] == DIFF_EQUAL) {829// Equality found.830equalities[equalitiesLength++] = pointer;831length_insertions1 = length_insertions2;832length_deletions1 = length_deletions2;833length_insertions2 = 0;834length_deletions2 = 0;835lastEquality = diffs[pointer][1];836} else {837// An insertion or deletion.838if (diffs[pointer][0] == DIFF_INSERT) {839length_insertions2 += diffs[pointer][1].length;840} else {841length_deletions2 += diffs[pointer][1].length;842}843// Eliminate an equality that is smaller or equal to the edits on both844// sides of it.845if (846lastEquality &&847lastEquality.length <=848Math.max(length_insertions1, length_deletions1) &&849lastEquality.length <= Math.max(length_insertions2, length_deletions2)850) {851// Duplicate record.852diffs.splice(853equalities[equalitiesLength - 1],8540,855new diff_match_patch.Diff(DIFF_DELETE, lastEquality),856);857// Change second copy to insert.858diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;859// Throw away the equality we just deleted.860equalitiesLength--;861// Throw away the previous equality (it needs to be reevaluated).862equalitiesLength--;863pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;864length_insertions1 = 0; // Reset the counters.865length_deletions1 = 0;866length_insertions2 = 0;867length_deletions2 = 0;868lastEquality = null;869changes = true;870}871}872pointer++;873}874875// Normalize the diff.876if (changes) {877this.diff_cleanupMerge(diffs);878}879this.diff_cleanupSemanticLossless(diffs);880881// Find any overlaps between deletions and insertions.882// e.g: <del>abcxxx</del><ins>xxxdef</ins>883// -> <del>abc</del>xxx<ins>def</ins>884// e.g: <del>xxxabc</del><ins>defxxx</ins>885// -> <ins>def</ins>xxx<del>abc</del>886// Only extract an overlap if it is as big as the edit ahead or behind it.887pointer = 1;888while (pointer < diffs.length) {889if (890diffs[pointer - 1][0] == DIFF_DELETE &&891diffs[pointer][0] == DIFF_INSERT892) {893var deletion = diffs[pointer - 1][1];894var insertion = diffs[pointer][1];895var overlap_length1 = this.diff_commonOverlap_(deletion, insertion);896var overlap_length2 = this.diff_commonOverlap_(insertion, deletion);897if (overlap_length1 >= overlap_length2) {898if (899overlap_length1 >= deletion.length / 2 ||900overlap_length1 >= insertion.length / 2901) {902// Overlap found. Insert an equality and trim the surrounding edits.903diffs.splice(904pointer,9050,906new diff_match_patch.Diff(907DIFF_EQUAL,908insertion.substring(0, overlap_length1),909),910);911diffs[pointer - 1][1] = deletion.substring(9120,913deletion.length - overlap_length1,914);915diffs[pointer + 1][1] = insertion.substring(overlap_length1);916pointer++;917}918} else {919if (920overlap_length2 >= deletion.length / 2 ||921overlap_length2 >= insertion.length / 2922) {923// Reverse overlap found.924// Insert an equality and swap and trim the surrounding edits.925diffs.splice(926pointer,9270,928new diff_match_patch.Diff(929DIFF_EQUAL,930deletion.substring(0, overlap_length2),931),932);933diffs[pointer - 1][0] = DIFF_INSERT;934diffs[pointer - 1][1] = insertion.substring(9350,936insertion.length - overlap_length2,937);938diffs[pointer + 1][0] = DIFF_DELETE;939diffs[pointer + 1][1] = deletion.substring(overlap_length2);940pointer++;941}942}943pointer++;944}945pointer++;946}947};948949/**950* Look for single edits surrounded on both sides by equalities951* which can be shifted sideways to align the edit to a word boundary.952* e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.953* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.954*/955diff_match_patch.prototype.diff_cleanupSemanticLossless = function (diffs) {956/**957* Given two strings, compute a score representing whether the internal958* boundary falls on logical boundaries.959* Scores range from 6 (best) to 0 (worst).960* Closure, but does not reference any external variables.961* @param {string} one First string.962* @param {string} two Second string.963* @return {number} The score.964* @private965*/966function diff_cleanupSemanticScore_(one, two) {967if (!one || !two) {968// Edges are the best.969return 6;970}971972// Each port of this function behaves slightly differently due to973// subtle differences in each language's definition of things like974// 'whitespace'. Since this function's purpose is largely cosmetic,975// the choice has been made to use each language's native features976// rather than force total conformity.977var char1 = one.charAt(one.length - 1);978var char2 = two.charAt(0);979var nonAlphaNumeric1 = char1.match(diff_match_patch.nonAlphaNumericRegex_);980var nonAlphaNumeric2 = char2.match(diff_match_patch.nonAlphaNumericRegex_);981var whitespace1 =982nonAlphaNumeric1 && char1.match(diff_match_patch.whitespaceRegex_);983var whitespace2 =984nonAlphaNumeric2 && char2.match(diff_match_patch.whitespaceRegex_);985var lineBreak1 =986whitespace1 && char1.match(diff_match_patch.linebreakRegex_);987var lineBreak2 =988whitespace2 && char2.match(diff_match_patch.linebreakRegex_);989var blankLine1 =990lineBreak1 && one.match(diff_match_patch.blanklineEndRegex_);991var blankLine2 =992lineBreak2 && two.match(diff_match_patch.blanklineStartRegex_);993994if (blankLine1 || blankLine2) {995// Five points for blank lines.996return 5;997} else if (lineBreak1 || lineBreak2) {998// Four points for line breaks.999return 4;1000} else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) {1001// Three points for end of sentences.1002return 3;1003} else if (whitespace1 || whitespace2) {1004// Two points for whitespace.1005return 2;1006} else if (nonAlphaNumeric1 || nonAlphaNumeric2) {1007// One point for non-alphanumeric.1008return 1;1009}1010return 0;1011}10121013var pointer = 1;1014// Intentionally ignore the first and last element (don't need checking).1015while (pointer < diffs.length - 1) {1016if (1017diffs[pointer - 1][0] == DIFF_EQUAL &&1018diffs[pointer + 1][0] == DIFF_EQUAL1019) {1020// This is a single edit surrounded by equalities.1021var equality1 = diffs[pointer - 1][1];1022var edit = diffs[pointer][1];1023var equality2 = diffs[pointer + 1][1];10241025// First, shift the edit as far left as possible.1026var commonOffset = this.diff_commonSuffix(equality1, edit);1027if (commonOffset) {1028var commonString = edit.substring(edit.length - commonOffset);1029equality1 = equality1.substring(0, equality1.length - commonOffset);1030edit = commonString + edit.substring(0, edit.length - commonOffset);1031equality2 = commonString + equality2;1032}10331034// Second, step character by character right, looking for the best fit.1035var bestEquality1 = equality1;1036var bestEdit = edit;1037var bestEquality2 = equality2;1038var bestScore =1039diff_cleanupSemanticScore_(equality1, edit) +1040diff_cleanupSemanticScore_(edit, equality2);1041while (edit.charAt(0) === equality2.charAt(0)) {1042equality1 += edit.charAt(0);1043edit = edit.substring(1) + equality2.charAt(0);1044equality2 = equality2.substring(1);1045var score =1046diff_cleanupSemanticScore_(equality1, edit) +1047diff_cleanupSemanticScore_(edit, equality2);1048// The >= encourages trailing rather than leading whitespace on edits.1049if (score >= bestScore) {1050bestScore = score;1051bestEquality1 = equality1;1052bestEdit = edit;1053bestEquality2 = equality2;1054}1055}10561057if (diffs[pointer - 1][1] != bestEquality1) {1058// We have an improvement, save it back to the diff.1059if (bestEquality1) {1060diffs[pointer - 1][1] = bestEquality1;1061} else {1062diffs.splice(pointer - 1, 1);1063pointer--;1064}1065diffs[pointer][1] = bestEdit;1066if (bestEquality2) {1067diffs[pointer + 1][1] = bestEquality2;1068} else {1069diffs.splice(pointer + 1, 1);1070pointer--;1071}1072}1073}1074pointer++;1075}1076};10771078// Define some regex patterns for matching boundaries.1079diff_match_patch.nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/;1080diff_match_patch.whitespaceRegex_ = /\s/;1081diff_match_patch.linebreakRegex_ = /[\r\n]/;1082diff_match_patch.blanklineEndRegex_ = /\n\r?\n$/;1083diff_match_patch.blanklineStartRegex_ = /^\r?\n\r?\n/;10841085/**1086* Reduce the number of edits by eliminating operationally trivial equalities.1087* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.1088*/1089diff_match_patch.prototype.diff_cleanupEfficiency = function (diffs) {1090var changes = false;1091var equalities = []; // Stack of indices where equalities are found.1092var equalitiesLength = 0; // Keeping our own length var is faster in JS.1093/** @type {?string} */1094var lastEquality = null;1095// Always equal to diffs[equalities[equalitiesLength - 1]][1]1096var pointer = 0; // Index of current position.1097// Is there an insertion operation before the last equality.1098var pre_ins = false;1099// Is there a deletion operation before the last equality.1100var pre_del = false;1101// Is there an insertion operation after the last equality.1102var post_ins = false;1103// Is there a deletion operation after the last equality.1104var post_del = false;1105while (pointer < diffs.length) {1106if (diffs[pointer][0] == DIFF_EQUAL) {1107// Equality found.1108if (1109diffs[pointer][1].length < this.Diff_EditCost &&1110(post_ins || post_del)1111) {1112// Candidate found.1113equalities[equalitiesLength++] = pointer;1114pre_ins = post_ins;1115pre_del = post_del;1116lastEquality = diffs[pointer][1];1117} else {1118// Not a candidate, and can never become one.1119equalitiesLength = 0;1120lastEquality = null;1121}1122post_ins = post_del = false;1123} else {1124// An insertion or deletion.1125if (diffs[pointer][0] == DIFF_DELETE) {1126post_del = true;1127} else {1128post_ins = true;1129}1130/*1131* Five types to be split:1132* <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>1133* <ins>A</ins>X<ins>C</ins><del>D</del>1134* <ins>A</ins><del>B</del>X<ins>C</ins>1135* <ins>A</del>X<ins>C</ins><del>D</del>1136* <ins>A</ins><del>B</del>X<del>C</del>1137*/1138if (1139lastEquality &&1140((pre_ins && pre_del && post_ins && post_del) ||1141(lastEquality.length < this.Diff_EditCost / 2 &&1142pre_ins + pre_del + post_ins + post_del == 3))1143) {1144// Duplicate record.1145diffs.splice(1146equalities[equalitiesLength - 1],11470,1148new diff_match_patch.Diff(DIFF_DELETE, lastEquality),1149);1150// Change second copy to insert.1151diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;1152equalitiesLength--; // Throw away the equality we just deleted;1153lastEquality = null;1154if (pre_ins && pre_del) {1155// No changes made which could affect previous entry, keep going.1156post_ins = post_del = true;1157equalitiesLength = 0;1158} else {1159equalitiesLength--; // Throw away the previous equality.1160pointer =1161equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;1162post_ins = post_del = false;1163}1164changes = true;1165}1166}1167pointer++;1168}11691170if (changes) {1171this.diff_cleanupMerge(diffs);1172}1173};11741175/**1176* Reorder and merge like edit sections. Merge equalities.1177* Any edit section can move as long as it doesn't cross an equality.1178* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.1179*/1180diff_match_patch.prototype.diff_cleanupMerge = function (diffs) {1181// Add a dummy entry at the end.1182diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, ""));1183var pointer = 0;1184var count_delete = 0;1185var count_insert = 0;1186var text_delete = "";1187var text_insert = "";1188var commonlength;1189while (pointer < diffs.length) {1190switch (diffs[pointer][0]) {1191case DIFF_INSERT:1192count_insert++;1193text_insert += diffs[pointer][1];1194pointer++;1195break;1196case DIFF_DELETE:1197count_delete++;1198text_delete += diffs[pointer][1];1199pointer++;1200break;1201case DIFF_EQUAL:1202// Upon reaching an equality, check for prior redundancies.1203if (count_delete + count_insert > 1) {1204if (count_delete !== 0 && count_insert !== 0) {1205// Factor out any common prefixies.1206commonlength = this.diff_commonPrefix(text_insert, text_delete);1207if (commonlength !== 0) {1208if (1209pointer - count_delete - count_insert > 0 &&1210diffs[pointer - count_delete - count_insert - 1][0] ==1211DIFF_EQUAL1212) {1213diffs[pointer - count_delete - count_insert - 1][1] +=1214text_insert.substring(0, commonlength);1215} else {1216diffs.splice(12170,12180,1219new diff_match_patch.Diff(1220DIFF_EQUAL,1221text_insert.substring(0, commonlength),1222),1223);1224pointer++;1225}1226text_insert = text_insert.substring(commonlength);1227text_delete = text_delete.substring(commonlength);1228}1229// Factor out any common suffixies.1230commonlength = this.diff_commonSuffix(text_insert, text_delete);1231if (commonlength !== 0) {1232diffs[pointer][1] =1233text_insert.substring(text_insert.length - commonlength) +1234diffs[pointer][1];1235text_insert = text_insert.substring(12360,1237text_insert.length - commonlength,1238);1239text_delete = text_delete.substring(12400,1241text_delete.length - commonlength,1242);1243}1244}1245// Delete the offending records and add the merged ones.1246pointer -= count_delete + count_insert;1247diffs.splice(pointer, count_delete + count_insert);1248if (text_delete.length) {1249diffs.splice(1250pointer,12510,1252new diff_match_patch.Diff(DIFF_DELETE, text_delete),1253);1254pointer++;1255}1256if (text_insert.length) {1257diffs.splice(1258pointer,12590,1260new diff_match_patch.Diff(DIFF_INSERT, text_insert),1261);1262pointer++;1263}1264pointer++;1265} else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL) {1266// Merge this equality with the previous one.1267diffs[pointer - 1][1] += diffs[pointer][1];1268diffs.splice(pointer, 1);1269} else {1270pointer++;1271}1272count_insert = 0;1273count_delete = 0;1274text_delete = "";1275text_insert = "";1276break;1277}1278}1279if (diffs[diffs.length - 1][1] === "") {1280diffs.pop(); // Remove the dummy entry at the end.1281}12821283// Second pass: look for single edits surrounded on both sides by equalities1284// which can be shifted sideways to eliminate an equality.1285// e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC1286var changes = false;1287pointer = 1;1288// Intentionally ignore the first and last element (don't need checking).1289while (pointer < diffs.length - 1) {1290if (1291diffs[pointer - 1][0] == DIFF_EQUAL &&1292diffs[pointer + 1][0] == DIFF_EQUAL1293) {1294// This is a single edit surrounded by equalities.1295if (1296diffs[pointer][1].substring(1297diffs[pointer][1].length - diffs[pointer - 1][1].length,1298) == diffs[pointer - 1][1]1299) {1300// Shift the edit over the previous equality.1301diffs[pointer][1] =1302diffs[pointer - 1][1] +1303diffs[pointer][1].substring(13040,1305diffs[pointer][1].length - diffs[pointer - 1][1].length,1306);1307diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];1308diffs.splice(pointer - 1, 1);1309changes = true;1310} else if (1311diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) ==1312diffs[pointer + 1][1]1313) {1314// Shift the edit over the next equality.1315diffs[pointer - 1][1] += diffs[pointer + 1][1];1316diffs[pointer][1] =1317diffs[pointer][1].substring(diffs[pointer + 1][1].length) +1318diffs[pointer + 1][1];1319diffs.splice(pointer + 1, 1);1320changes = true;1321}1322}1323pointer++;1324}1325// If shifts were made, the diff needs reordering and another shift sweep.1326if (changes) {1327this.diff_cleanupMerge(diffs);1328}1329};13301331/**1332* loc is a location in text1, compute and return the equivalent location in1333* text2.1334* e.g. 'The cat' vs 'The big cat', 1->1, 5->81335* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.1336* @param {number} loc Location within text1.1337* @return {number} Location within text2.1338*/1339diff_match_patch.prototype.diff_xIndex = function (diffs, loc) {1340var chars1 = 0;1341var chars2 = 0;1342var last_chars1 = 0;1343var last_chars2 = 0;1344var x;1345for (x = 0; x < diffs.length; x++) {1346if (diffs[x][0] !== DIFF_INSERT) {1347// Equality or deletion.1348chars1 += diffs[x][1].length;1349}1350if (diffs[x][0] !== DIFF_DELETE) {1351// Equality or insertion.1352chars2 += diffs[x][1].length;1353}1354if (chars1 > loc) {1355// Overshot the location.1356break;1357}1358last_chars1 = chars1;1359last_chars2 = chars2;1360}1361// Was the location was deleted?1362if (diffs.length != x && diffs[x][0] === DIFF_DELETE) {1363return last_chars2;1364}1365// Add the remaining character length.1366return last_chars2 + (loc - last_chars1);1367};13681369/**1370* Convert a diff array into a pretty HTML report.1371* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.1372* @return {string} HTML representation.1373*/1374diff_match_patch.prototype.diff_prettyHtml = function (diffs) {1375var html = [];1376var pattern_amp = /&/g;1377var pattern_lt = /</g;1378var pattern_gt = />/g;1379var pattern_para = /\n/g;1380for (var x = 0; x < diffs.length; x++) {1381var op = diffs[x][0]; // Operation (insert, delete, equal)1382var data = diffs[x][1]; // Text of change.1383var text = data1384.replace(pattern_amp, "&")1385.replace(pattern_lt, "<")1386.replace(pattern_gt, ">")1387.replace(pattern_para, "¶<br>");1388switch (op) {1389case DIFF_INSERT:1390html[x] = '<ins style="background:#e6ffe6;">' + text + "</ins>";1391break;1392case DIFF_DELETE:1393html[x] = '<del style="background:#ffe6e6;">' + text + "</del>";1394break;1395case DIFF_EQUAL:1396html[x] = "<span>" + text + "</span>";1397break;1398}1399}1400return html.join("");1401};14021403/**1404* Compute and return the source text (all equalities and deletions).1405* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.1406* @return {string} Source text.1407*/1408diff_match_patch.prototype.diff_text1 = function (diffs) {1409var text = [];1410for (var x = 0; x < diffs.length; x++) {1411if (diffs[x][0] !== DIFF_INSERT) {1412text[x] = diffs[x][1];1413}1414}1415return text.join("");1416};14171418/**1419* Compute and return the destination text (all equalities and insertions).1420* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.1421* @return {string} Destination text.1422*/1423diff_match_patch.prototype.diff_text2 = function (diffs) {1424var text = [];1425for (var x = 0; x < diffs.length; x++) {1426if (diffs[x][0] !== DIFF_DELETE) {1427text[x] = diffs[x][1];1428}1429}1430return text.join("");1431};14321433/**1434* Compute the Levenshtein distance; the number of inserted, deleted or1435* substituted characters.1436* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.1437* @return {number} Number of changes.1438*/1439diff_match_patch.prototype.diff_levenshtein = function (diffs) {1440var levenshtein = 0;1441var insertions = 0;1442var deletions = 0;1443for (var x = 0; x < diffs.length; x++) {1444var op = diffs[x][0];1445var data = diffs[x][1];1446switch (op) {1447case DIFF_INSERT:1448insertions += data.length;1449break;1450case DIFF_DELETE:1451deletions += data.length;1452break;1453case DIFF_EQUAL:1454// A deletion and an insertion is one substitution.1455levenshtein += Math.max(insertions, deletions);1456insertions = 0;1457deletions = 0;1458break;1459}1460}1461levenshtein += Math.max(insertions, deletions);1462return levenshtein;1463};14641465/**1466* Crush the diff into an encoded string which describes the operations1467* required to transform text1 into text2.1468* E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'.1469* Operations are tab-separated. Inserted text is escaped using %xx notation.1470* @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.1471* @return {string} Delta text.1472*/1473diff_match_patch.prototype.diff_toDelta = function (diffs) {1474var text = [];1475for (var x = 0; x < diffs.length; x++) {1476switch (diffs[x][0]) {1477case DIFF_INSERT:1478text[x] = "+" + encodeURI(diffs[x][1]);1479break;1480case DIFF_DELETE:1481text[x] = "-" + diffs[x][1].length;1482break;1483case DIFF_EQUAL:1484text[x] = "=" + diffs[x][1].length;1485break;1486}1487}1488return text.join("\t").replace(/%20/g, " ");1489};14901491/**1492* Given the original text1, and an encoded string which describes the1493* operations required to transform text1 into text2, compute the full diff.1494* @param {string} text1 Source string for the diff.1495* @param {string} delta Delta text.1496* @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.1497* @throws {!Error} If invalid input.1498*/1499diff_match_patch.prototype.diff_fromDelta = function (text1, delta) {1500var diffs = [];1501var diffsLength = 0; // Keeping our own length var is faster in JS.1502var pointer = 0; // Cursor in text11503var tokens = delta.split(/\t/g);1504for (var x = 0; x < tokens.length; x++) {1505// Each token begins with a one character parameter which specifies the1506// operation of this token (delete, insert, equality).1507var param = tokens[x].substring(1);1508switch (tokens[x].charAt(0)) {1509case "+":1510try {1511diffs[diffsLength++] = new diff_match_patch.Diff(1512DIFF_INSERT,1513decodeURI(param),1514);1515} catch (ex) {1516// Malformed URI sequence.1517throw new Error("Illegal escape in diff_fromDelta: " + param);1518}1519break;1520case "-":1521// Fall through.1522case "=":1523var n = parseInt(param, 10);1524if (isNaN(n) || n < 0) {1525throw new Error("Invalid number in diff_fromDelta: " + param);1526}1527var text = text1.substring(pointer, (pointer += n));1528if (tokens[x].charAt(0) == "=") {1529diffs[diffsLength++] = new diff_match_patch.Diff(DIFF_EQUAL, text);1530} else {1531diffs[diffsLength++] = new diff_match_patch.Diff(DIFF_DELETE, text);1532}1533break;1534default:1535// Blank tokens are ok (from a trailing \t).1536// Anything else is an error.1537if (tokens[x]) {1538throw new Error(1539"Invalid diff operation in diff_fromDelta: " + tokens[x],1540);1541}1542}1543}1544if (pointer != text1.length) {1545throw new Error(1546"Delta length (" +1547pointer +1548") does not equal source text length (" +1549text1.length +1550").",1551);1552}1553return diffs;1554};15551556// MATCH FUNCTIONS15571558/**1559* Locate the best instance of 'pattern' in 'text' near 'loc'.1560* @param {string} text The text to search.1561* @param {string} pattern The pattern to search for.1562* @param {number} loc The location to search around.1563* @return {number} Best match index or -1.1564*/1565diff_match_patch.prototype.match_main = function (text, pattern, loc) {1566// Check for null inputs.1567if (text == null || pattern == null || loc == null) {1568throw new Error("Null input. (match_main)");1569}15701571loc = Math.max(0, Math.min(loc, text.length));1572if (text == pattern) {1573// Shortcut (potentially not guaranteed by the algorithm)1574return 0;1575} else if (!text.length) {1576// Nothing to match.1577return -1;1578} else if (text.substring(loc, loc + pattern.length) == pattern) {1579// Perfect match at the perfect spot! (Includes case of null pattern)1580return loc;1581} else {1582// Do a fuzzy compare.1583return this.match_bitap_(text, pattern, loc);1584}1585};15861587/**1588* Locate the best instance of 'pattern' in 'text' near 'loc' using the1589* Bitap algorithm.1590* @param {string} text The text to search.1591* @param {string} pattern The pattern to search for.1592* @param {number} loc The location to search around.1593* @return {number} Best match index or -1.1594* @private1595*/1596diff_match_patch.prototype.match_bitap_ = function (text, pattern, loc) {1597if (pattern.length > this.Match_MaxBits) {1598throw new Error("Pattern too long for this browser.");1599}16001601// Initialise the alphabet.1602var s = this.match_alphabet_(pattern);16031604var dmp = this; // 'this' becomes 'window' in a closure.16051606/**1607* Compute and return the score for a match with e errors and x location.1608* Accesses loc and pattern through being a closure.1609* @param {number} e Number of errors in match.1610* @param {number} x Location of match.1611* @return {number} Overall score for match (0.0 = good, 1.0 = bad).1612* @private1613*/1614function match_bitapScore_(e, x) {1615var accuracy = e / pattern.length;1616var proximity = Math.abs(loc - x);1617if (!dmp.Match_Distance) {1618// Dodge divide by zero error.1619return proximity ? 1.0 : accuracy;1620}1621return accuracy + proximity / dmp.Match_Distance;1622}16231624// Highest score beyond which we give up.1625var score_threshold = this.Match_Threshold;1626// Is there a nearby exact match? (speedup)1627var best_loc = text.indexOf(pattern, loc);1628if (best_loc != -1) {1629score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold);1630// What about in the other direction? (speedup)1631best_loc = text.lastIndexOf(pattern, loc + pattern.length);1632if (best_loc != -1) {1633score_threshold = Math.min(1634match_bitapScore_(0, best_loc),1635score_threshold,1636);1637}1638}16391640// Initialise the bit arrays.1641var matchmask = 1 << (pattern.length - 1);1642best_loc = -1;16431644var bin_min, bin_mid;1645var bin_max = pattern.length + text.length;1646var last_rd;1647for (var d = 0; d < pattern.length; d++) {1648// Scan for the best match; each iteration allows for one more error.1649// Run a binary search to determine how far from 'loc' we can stray at this1650// error level.1651bin_min = 0;1652bin_mid = bin_max;1653while (bin_min < bin_mid) {1654if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) {1655bin_min = bin_mid;1656} else {1657bin_max = bin_mid;1658}1659bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min);1660}1661// Use the result from this iteration as the maximum for the next.1662bin_max = bin_mid;1663var start = Math.max(1, loc - bin_mid + 1);1664var finish = Math.min(loc + bin_mid, text.length) + pattern.length;16651666var rd = Array(finish + 2);1667rd[finish + 1] = (1 << d) - 1;1668for (var j = finish; j >= start; j--) {1669// The alphabet (s) is a sparse hash, so the following line generates1670// warnings.1671var charMatch = s[text.charAt(j - 1)];1672if (d === 0) {1673// First pass: exact match.1674rd[j] = ((rd[j + 1] << 1) | 1) & charMatch;1675} else {1676// Subsequent passes: fuzzy match.1677rd[j] =1678(((rd[j + 1] << 1) | 1) & charMatch) |1679(((last_rd[j + 1] | last_rd[j]) << 1) | 1) |1680last_rd[j + 1];1681}1682if (rd[j] & matchmask) {1683var score = match_bitapScore_(d, j - 1);1684// This match will almost certainly be better than any existing match.1685// But check anyway.1686if (score <= score_threshold) {1687// Told you so.1688score_threshold = score;1689best_loc = j - 1;1690if (best_loc > loc) {1691// When passing loc, don't exceed our current distance from loc.1692start = Math.max(1, 2 * loc - best_loc);1693} else {1694// Already passed loc, downhill from here on in.1695break;1696}1697}1698}1699}1700// No hope for a (better) match at greater error levels.1701if (match_bitapScore_(d + 1, loc) > score_threshold) {1702break;1703}1704last_rd = rd;1705}1706return best_loc;1707};17081709/**1710* Initialise the alphabet for the Bitap algorithm.1711* @param {string} pattern The text to encode.1712* @return {!Object} Hash of character locations.1713* @private1714*/1715diff_match_patch.prototype.match_alphabet_ = function (pattern) {1716var s = {};1717for (var i = 0; i < pattern.length; i++) {1718s[pattern.charAt(i)] = 0;1719}1720for (var i = 0; i < pattern.length; i++) {1721s[pattern.charAt(i)] |= 1 << (pattern.length - i - 1);1722}1723return s;1724};17251726// PATCH FUNCTIONS17271728/**1729* Increase the context until it is unique,1730* but don't let the pattern expand beyond Match_MaxBits.1731* @param {!diff_match_patch.patch_obj} patch The patch to grow.1732* @param {string} text Source text.1733* @private1734*/1735diff_match_patch.prototype.patch_addContext_ = function (patch, text) {1736if (text.length == 0) {1737return;1738}1739if (patch.start2 === null) {1740throw Error("patch not initialized");1741}1742var pattern = text.substring(patch.start2, patch.start2 + patch.length1);1743var padding = 0;17441745// Look for the first and last matches of pattern in text. If two different1746// matches are found, increase the pattern length.1747while (1748text.indexOf(pattern) != text.lastIndexOf(pattern) &&1749pattern.length < this.Match_MaxBits - this.Patch_Margin - this.Patch_Margin1750) {1751padding += this.Patch_Margin;1752pattern = text.substring(1753patch.start2 - padding,1754patch.start2 + patch.length1 + padding,1755);1756}1757// Add one chunk for good luck.1758padding += this.Patch_Margin;17591760// Add the prefix.1761var prefix = text.substring(patch.start2 - padding, patch.start2);1762if (prefix) {1763patch.diffs.unshift(new diff_match_patch.Diff(DIFF_EQUAL, prefix));1764}1765// Add the suffix.1766var suffix = text.substring(1767patch.start2 + patch.length1,1768patch.start2 + patch.length1 + padding,1769);1770if (suffix) {1771patch.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, suffix));1772}17731774// Roll back the start points.1775patch.start1 -= prefix.length;1776patch.start2 -= prefix.length;1777// Extend the lengths.1778patch.length1 += prefix.length + suffix.length;1779patch.length2 += prefix.length + suffix.length;1780};17811782/**1783* Compute a list of patches to turn text1 into text2.1784* Use diffs if provided, otherwise compute it ourselves.1785* There are four ways to call this function, depending on what data is1786* available to the caller:1787* Method 1:1788* a = text1, b = text21789* Method 2:1790* a = diffs1791* Method 3 (optimal):1792* a = text1, b = diffs1793* Method 4 (deprecated, use method 3):1794* a = text1, b = text2, c = diffs1795*1796* @param {string|!Array.<!diff_match_patch.Diff>} a text1 (methods 1,3,4) or1797* Array of diff tuples for text1 to text2 (method 2).1798* @param {string|!Array.<!diff_match_patch.Diff>} opt_b text2 (methods 1,4) or1799* Array of diff tuples for text1 to text2 (method 3) or undefined (method 2).1800* @param {string|!Array.<!diff_match_patch.Diff>} opt_c Array of diff tuples1801* for text1 to text2 (method 4) or undefined (methods 1,2,3).1802* @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.1803*/1804diff_match_patch.prototype.patch_make = function (a, opt_b, opt_c) {1805var text1, diffs;1806if (1807typeof a == "string" &&1808typeof opt_b == "string" &&1809typeof opt_c == "undefined"1810) {1811// Method 1: text1, text21812// Compute diffs from text1 and text2.1813text1 = /** @type {string} */ (a);1814diffs = this.diff_main(text1, /** @type {string} */ (opt_b), true);1815if (diffs.length > 2) {1816this.diff_cleanupSemantic(diffs);1817this.diff_cleanupEfficiency(diffs);1818}1819} else if (1820a &&1821typeof a == "object" &&1822typeof opt_b == "undefined" &&1823typeof opt_c == "undefined"1824) {1825// Method 2: diffs1826// Compute text1 from diffs.1827diffs = /** @type {!Array.<!diff_match_patch.Diff>} */ (a);1828text1 = this.diff_text1(diffs);1829} else if (1830typeof a == "string" &&1831opt_b &&1832typeof opt_b == "object" &&1833typeof opt_c == "undefined"1834) {1835// Method 3: text1, diffs1836text1 = /** @type {string} */ (a);1837diffs = /** @type {!Array.<!diff_match_patch.Diff>} */ (opt_b);1838} else if (1839typeof a == "string" &&1840typeof opt_b == "string" &&1841opt_c &&1842typeof opt_c == "object"1843) {1844// Method 4: text1, text2, diffs1845// text2 is not used.1846text1 = /** @type {string} */ (a);1847diffs = /** @type {!Array.<!diff_match_patch.Diff>} */ (opt_c);1848} else {1849throw new Error("Unknown call format to patch_make.");1850}18511852if (diffs.length === 0) {1853return []; // Get rid of the null case.1854}1855var patches = [];1856var patch = new diff_match_patch.patch_obj();1857var patchDiffLength = 0; // Keeping our own length var is faster in JS.1858var char_count1 = 0; // Number of characters into the text1 string.1859var char_count2 = 0; // Number of characters into the text2 string.1860// Start with text1 (prepatch_text) and apply the diffs until we arrive at1861// text2 (postpatch_text). We recreate the patches one by one to determine1862// context info.1863var prepatch_text = text1;1864var postpatch_text = text1;1865for (var x = 0; x < diffs.length; x++) {1866var diff_type = diffs[x][0];1867var diff_text = diffs[x][1];18681869if (!patchDiffLength && diff_type !== DIFF_EQUAL) {1870// A new patch starts here.1871patch.start1 = char_count1;1872patch.start2 = char_count2;1873}18741875switch (diff_type) {1876case DIFF_INSERT:1877patch.diffs[patchDiffLength++] = diffs[x];1878patch.length2 += diff_text.length;1879postpatch_text =1880postpatch_text.substring(0, char_count2) +1881diff_text +1882postpatch_text.substring(char_count2);1883break;1884case DIFF_DELETE:1885patch.length1 += diff_text.length;1886patch.diffs[patchDiffLength++] = diffs[x];1887postpatch_text =1888postpatch_text.substring(0, char_count2) +1889postpatch_text.substring(char_count2 + diff_text.length);1890break;1891case DIFF_EQUAL:1892if (1893diff_text.length <= 2 * this.Patch_Margin &&1894patchDiffLength &&1895diffs.length != x + 11896) {1897// Small equality inside a patch.1898patch.diffs[patchDiffLength++] = diffs[x];1899patch.length1 += diff_text.length;1900patch.length2 += diff_text.length;1901} else if (diff_text.length >= 2 * this.Patch_Margin) {1902// Time for a new patch.1903if (patchDiffLength) {1904this.patch_addContext_(patch, prepatch_text);1905patches.push(patch);1906patch = new diff_match_patch.patch_obj();1907patchDiffLength = 0;1908// Unlike Unidiff, our patch lists have a rolling context.1909// https://github.com/google/diff-match-patch/wiki/Unidiff1910// Update prepatch text & pos to reflect the application of the1911// just completed patch.1912prepatch_text = postpatch_text;1913char_count1 = char_count2;1914}1915}1916break;1917}19181919// Update the current character count.1920if (diff_type !== DIFF_INSERT) {1921char_count1 += diff_text.length;1922}1923if (diff_type !== DIFF_DELETE) {1924char_count2 += diff_text.length;1925}1926}1927// Pick up the leftover patch if not empty.1928if (patchDiffLength) {1929this.patch_addContext_(patch, prepatch_text);1930patches.push(patch);1931}19321933return patches;1934};19351936/**1937* Given an array of patches, return another array that is identical.1938* @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.1939* @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.1940*/1941diff_match_patch.prototype.patch_deepCopy = function (patches) {1942// Making deep copies is hard in JavaScript.1943var patchesCopy = [];1944for (var x = 0; x < patches.length; x++) {1945var patch = patches[x];1946var patchCopy = new diff_match_patch.patch_obj();1947patchCopy.diffs = [];1948for (var y = 0; y < patch.diffs.length; y++) {1949patchCopy.diffs[y] = new diff_match_patch.Diff(1950patch.diffs[y][0],1951patch.diffs[y][1],1952);1953}1954patchCopy.start1 = patch.start1;1955patchCopy.start2 = patch.start2;1956patchCopy.length1 = patch.length1;1957patchCopy.length2 = patch.length2;1958patchesCopy[x] = patchCopy;1959}1960return patchesCopy;1961};19621963/**1964* Merge a set of patches onto the text. Return a patched text, as well1965* as a list of true/false values indicating which patches were applied.1966* @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.1967* @param {string} text Old text.1968* @return {!Array.<string|!Array.<boolean>>} Two element Array, containing the1969* new text and an array of boolean values.1970*/1971diff_match_patch.prototype.patch_apply = function (patches, text) {1972if (patches.length == 0) {1973return [text, []];1974}19751976// Deep copy the patches so that no changes are made to originals.1977patches = this.patch_deepCopy(patches);19781979var nullPadding = this.patch_addPadding(patches);1980text = nullPadding + text + nullPadding;19811982this.patch_splitMax(patches);1983// delta keeps track of the offset between the expected and actual location1984// of the previous patch. If there are patches expected at positions 10 and1985// 20, but the first patch was found at 12, delta is 2 and the second patch1986// has an effective expected position of 22.1987var delta = 0;1988var results = [];1989for (var x = 0; x < patches.length; x++) {1990var expected_loc = patches[x].start2 + delta;1991var text1 = this.diff_text1(patches[x].diffs);1992var start_loc;1993var end_loc = -1;1994if (text1.length > this.Match_MaxBits) {1995// patch_splitMax will only provide an oversized pattern in the case of1996// a monster delete.1997start_loc = this.match_main(1998text,1999text1.substring(0, this.Match_MaxBits),2000expected_loc,2001);2002if (start_loc != -1) {2003end_loc = this.match_main(2004text,2005text1.substring(text1.length - this.Match_MaxBits),2006expected_loc + text1.length - this.Match_MaxBits,2007);2008if (end_loc == -1 || start_loc >= end_loc) {2009// Can't find valid trailing context. Drop this patch.2010start_loc = -1;2011}2012}2013} else {2014start_loc = this.match_main(text, text1, expected_loc);2015}2016if (start_loc == -1) {2017// No match found. :(2018results[x] = false;2019// Subtract the delta for this failed patch from subsequent patches.2020delta -= patches[x].length2 - patches[x].length1;2021} else {2022// Found a match. :)2023results[x] = true;2024delta = start_loc - expected_loc;2025var text2;2026if (end_loc == -1) {2027text2 = text.substring(start_loc, start_loc + text1.length);2028} else {2029text2 = text.substring(start_loc, end_loc + this.Match_MaxBits);2030}2031if (text1 == text2) {2032// Perfect match, just shove the replacement text in.2033text =2034text.substring(0, start_loc) +2035this.diff_text2(patches[x].diffs) +2036text.substring(start_loc + text1.length);2037} else {2038// Imperfect match. Run a diff to get a framework of equivalent2039// indices.2040var diffs = this.diff_main(text1, text2, false);2041if (2042text1.length > this.Match_MaxBits &&2043this.diff_levenshtein(diffs) / text1.length >2044this.Patch_DeleteThreshold2045) {2046// The end points match, but the content is unacceptably bad.2047results[x] = false;2048} else {2049this.diff_cleanupSemanticLossless(diffs);2050var index1 = 0;2051var index2;2052for (var y = 0; y < patches[x].diffs.length; y++) {2053var mod = patches[x].diffs[y];2054if (mod[0] !== DIFF_EQUAL) {2055index2 = this.diff_xIndex(diffs, index1);2056}2057if (mod[0] === DIFF_INSERT) {2058// Insertion2059text =2060text.substring(0, start_loc + index2) +2061mod[1] +2062text.substring(start_loc + index2);2063} else if (mod[0] === DIFF_DELETE) {2064// Deletion2065text =2066text.substring(0, start_loc + index2) +2067text.substring(2068start_loc + this.diff_xIndex(diffs, index1 + mod[1].length),2069);2070}2071if (mod[0] !== DIFF_DELETE) {2072index1 += mod[1].length;2073}2074}2075}2076}2077}2078}2079// Strip the padding off.2080text = text.substring(nullPadding.length, text.length - nullPadding.length);2081return [text, results];2082};20832084/**2085* Add some padding on text start and end so that edges can match something.2086* Intended to be called only from within patch_apply.2087* @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.2088* @return {string} The padding string added to each side.2089*/2090diff_match_patch.prototype.patch_addPadding = function (patches) {2091var paddingLength = this.Patch_Margin;2092var nullPadding = "";2093for (var x = 1; x <= paddingLength; x++) {2094nullPadding += String.fromCharCode(x);2095}20962097// Bump all the patches forward.2098for (var x = 0; x < patches.length; x++) {2099patches[x].start1 += paddingLength;2100patches[x].start2 += paddingLength;2101}21022103// Add some padding on start of first diff.2104var patch = patches[0];2105var diffs = patch.diffs;2106if (diffs.length == 0 || diffs[0][0] != DIFF_EQUAL) {2107// Add nullPadding equality.2108diffs.unshift(new diff_match_patch.Diff(DIFF_EQUAL, nullPadding));2109patch.start1 -= paddingLength; // Should be 0.2110patch.start2 -= paddingLength; // Should be 0.2111patch.length1 += paddingLength;2112patch.length2 += paddingLength;2113} else if (paddingLength > diffs[0][1].length) {2114// Grow first equality.2115var extraLength = paddingLength - diffs[0][1].length;2116diffs[0][1] = nullPadding.substring(diffs[0][1].length) + diffs[0][1];2117patch.start1 -= extraLength;2118patch.start2 -= extraLength;2119patch.length1 += extraLength;2120patch.length2 += extraLength;2121}21222123// Add some padding on end of last diff.2124patch = patches[patches.length - 1];2125diffs = patch.diffs;2126if (diffs.length == 0 || diffs[diffs.length - 1][0] != DIFF_EQUAL) {2127// Add nullPadding equality.2128diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, nullPadding));2129patch.length1 += paddingLength;2130patch.length2 += paddingLength;2131} else if (paddingLength > diffs[diffs.length - 1][1].length) {2132// Grow last equality.2133var extraLength = paddingLength - diffs[diffs.length - 1][1].length;2134diffs[diffs.length - 1][1] += nullPadding.substring(0, extraLength);2135patch.length1 += extraLength;2136patch.length2 += extraLength;2137}21382139return nullPadding;2140};21412142/**2143* Look through the patches and break up any which are longer than the maximum2144* limit of the match algorithm.2145* Intended to be called only from within patch_apply.2146* @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.2147*/2148diff_match_patch.prototype.patch_splitMax = function (patches) {2149var patch_size = this.Match_MaxBits;2150for (var x = 0; x < patches.length; x++) {2151if (patches[x].length1 <= patch_size) {2152continue;2153}2154var bigpatch = patches[x];2155// Remove the big old patch.2156patches.splice(x--, 1);2157var start1 = bigpatch.start1;2158var start2 = bigpatch.start2;2159var precontext = "";2160while (bigpatch.diffs.length !== 0) {2161// Create one of several smaller patches.2162var patch = new diff_match_patch.patch_obj();2163var empty = true;2164patch.start1 = start1 - precontext.length;2165patch.start2 = start2 - precontext.length;2166if (precontext !== "") {2167patch.length1 = patch.length2 = precontext.length;2168patch.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, precontext));2169}2170while (2171bigpatch.diffs.length !== 0 &&2172patch.length1 < patch_size - this.Patch_Margin2173) {2174var diff_type = bigpatch.diffs[0][0];2175var diff_text = bigpatch.diffs[0][1];2176if (diff_type === DIFF_INSERT) {2177// Insertions are harmless.2178patch.length2 += diff_text.length;2179start2 += diff_text.length;2180patch.diffs.push(bigpatch.diffs.shift());2181empty = false;2182} else if (2183diff_type === DIFF_DELETE &&2184patch.diffs.length == 1 &&2185patch.diffs[0][0] == DIFF_EQUAL &&2186diff_text.length > 2 * patch_size2187) {2188// This is a large deletion. Let it pass in one chunk.2189patch.length1 += diff_text.length;2190start1 += diff_text.length;2191empty = false;2192patch.diffs.push(new diff_match_patch.Diff(diff_type, diff_text));2193bigpatch.diffs.shift();2194} else {2195// Deletion or equality. Only take as much as we can stomach.2196diff_text = diff_text.substring(21970,2198patch_size - patch.length1 - this.Patch_Margin,2199);2200patch.length1 += diff_text.length;2201start1 += diff_text.length;2202if (diff_type === DIFF_EQUAL) {2203patch.length2 += diff_text.length;2204start2 += diff_text.length;2205} else {2206empty = false;2207}2208patch.diffs.push(new diff_match_patch.Diff(diff_type, diff_text));2209if (diff_text == bigpatch.diffs[0][1]) {2210bigpatch.diffs.shift();2211} else {2212bigpatch.diffs[0][1] = bigpatch.diffs[0][1].substring(2213diff_text.length,2214);2215}2216}2217}2218// Compute the head context for the next patch.2219precontext = this.diff_text2(patch.diffs);2220precontext = precontext.substring(precontext.length - this.Patch_Margin);2221// Append the end context for this patch.2222var postcontext = this.diff_text1(bigpatch.diffs).substring(22230,2224this.Patch_Margin,2225);2226if (postcontext !== "") {2227patch.length1 += postcontext.length;2228patch.length2 += postcontext.length;2229if (2230patch.diffs.length !== 0 &&2231patch.diffs[patch.diffs.length - 1][0] === DIFF_EQUAL2232) {2233patch.diffs[patch.diffs.length - 1][1] += postcontext;2234} else {2235patch.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, postcontext));2236}2237}2238if (!empty) {2239patches.splice(++x, 0, patch);2240}2241}2242}2243};22442245/**2246* Take a list of patches and return a textual representation.2247* @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.2248* @return {string} Text representation of patches.2249*/2250diff_match_patch.prototype.patch_toText = function (patches) {2251var text = [];2252for (var x = 0; x < patches.length; x++) {2253text[x] = patches[x];2254}2255return text.join("");2256};22572258/**2259* Parse a textual representation of patches and return a list of Patch objects.2260* @param {string} textline Text representation of patches.2261* @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.2262* @throws {!Error} If invalid input.2263*/2264diff_match_patch.prototype.patch_fromText = function (textline) {2265var patches = [];2266if (!textline) {2267return patches;2268}2269var text = textline.split("\n");2270var textPointer = 0;2271var patchHeader = /^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;2272while (textPointer < text.length) {2273var m = text[textPointer].match(patchHeader);2274if (!m) {2275throw new Error("Invalid patch string: " + text[textPointer]);2276}2277var patch = new diff_match_patch.patch_obj();2278patches.push(patch);2279patch.start1 = parseInt(m[1], 10);2280if (m[2] === "") {2281patch.start1--;2282patch.length1 = 1;2283} else if (m[2] == "0") {2284patch.length1 = 0;2285} else {2286patch.start1--;2287patch.length1 = parseInt(m[2], 10);2288}22892290patch.start2 = parseInt(m[3], 10);2291if (m[4] === "") {2292patch.start2--;2293patch.length2 = 1;2294} else if (m[4] == "0") {2295patch.length2 = 0;2296} else {2297patch.start2--;2298patch.length2 = parseInt(m[4], 10);2299}2300textPointer++;23012302while (textPointer < text.length) {2303var sign = text[textPointer].charAt(0);2304try {2305var line = decodeURI(text[textPointer].substring(1));2306} catch (ex) {2307// Malformed URI sequence.2308throw new Error("Illegal escape in patch_fromText: " + line);2309}2310if (sign == "-") {2311// Deletion.2312patch.diffs.push(new diff_match_patch.Diff(DIFF_DELETE, line));2313} else if (sign == "+") {2314// Insertion.2315patch.diffs.push(new diff_match_patch.Diff(DIFF_INSERT, line));2316} else if (sign == " ") {2317// Minor equality.2318patch.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, line));2319} else if (sign == "@") {2320// Start of next patch.2321break;2322} else if (sign === "") {2323// Blank line? Whatever.2324} else {2325// WTF?2326throw new Error('Invalid patch mode "' + sign + '" in: ' + line);2327}2328textPointer++;2329}2330}2331return patches;2332};23332334/**2335* Class representing one patch operation.2336* @constructor2337*/2338diff_match_patch.patch_obj = function () {2339/** @type {!Array.<!diff_match_patch.Diff>} */2340this.diffs = [];2341/** @type {?number} */2342this.start1 = null;2343/** @type {?number} */2344this.start2 = null;2345/** @type {number} */2346this.length1 = 0;2347/** @type {number} */2348this.length2 = 0;2349};23502351/**2352* Emulate GNU diff's format.2353* Header: @@ -382,8 +481,9 @@2354* Indices are printed as 1-based, not 0-based.2355* @return {string} The GNU diff string.2356*/2357diff_match_patch.patch_obj.prototype.toString = function () {2358var coords1, coords2;2359if (this.length1 === 0) {2360coords1 = this.start1 + ",0";2361} else if (this.length1 == 1) {2362coords1 = this.start1 + 1;2363} else {2364coords1 = this.start1 + 1 + "," + this.length1;2365}2366if (this.length2 === 0) {2367coords2 = this.start2 + ",0";2368} else if (this.length2 == 1) {2369coords2 = this.start2 + 1;2370} else {2371coords2 = this.start2 + 1 + "," + this.length2;2372}2373var text = ["@@ -" + coords1 + " +" + coords2 + " @@\n"];2374var op;2375// Escape the body of the patch with %xx notation.2376for (var x = 0; x < this.diffs.length; x++) {2377switch (this.diffs[x][0]) {2378case DIFF_INSERT:2379op = "+";2380break;2381case DIFF_DELETE:2382op = "-";2383break;2384case DIFF_EQUAL:2385op = " ";2386break;2387}2388text[x + 1] = op + encodeURI(this.diffs[x][1]) + "\n";2389}2390return text.join("").replace(/%20/g, " ");2391};239223932394